Optionally dump "all" PostgreSQL databases to separate files instead of one combined dump file (#438, #560).
This commit is contained in:
parent
437fd4dbae
commit
f67c544be6
6 changed files with 221 additions and 70 deletions
3
NEWS
3
NEWS
|
@ -1,4 +1,7 @@
|
||||||
1.7.6.dev0
|
1.7.6.dev0
|
||||||
|
* #438, #560: Optionally dump "all" PostgreSQL databases to separate files instead of one combined
|
||||||
|
dump file, allowing more convenient restores of individual databases. You can enable this by
|
||||||
|
specifying the database dump "format" option when the database is named "all".
|
||||||
* #602: Fix logs that interfere with JSON output by making warnings go to stderr instead of stdout.
|
* #602: Fix logs that interfere with JSON output by making warnings go to stderr instead of stdout.
|
||||||
|
|
||||||
1.7.5
|
1.7.5
|
||||||
|
|
|
@ -691,10 +691,13 @@ properties:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
Database name (required if using this hook). Or
|
Database name (required if using this hook). Or
|
||||||
"all" to dump all databases on the host. Note
|
"all" to dump all databases on the host. (Also
|
||||||
that using this database hook implicitly enables
|
set the "format" to dump each database to a
|
||||||
both read_special and one_file_system (see
|
separate file instead of one combined file.)
|
||||||
above) to support dump and restore streaming.
|
Note that using this database hook implicitly
|
||||||
|
enables both read_special and one_file_system
|
||||||
|
(see above) to support dump and restore
|
||||||
|
streaming.
|
||||||
example: users
|
example: users
|
||||||
hostname:
|
hostname:
|
||||||
type: string
|
type: string
|
||||||
|
@ -729,9 +732,14 @@ properties:
|
||||||
description: |
|
description: |
|
||||||
Database dump output format. One of "plain",
|
Database dump output format. One of "plain",
|
||||||
"custom", "directory", or "tar". Defaults to
|
"custom", "directory", or "tar". Defaults to
|
||||||
"custom" (unlike raw pg_dump). See pg_dump
|
"custom" (unlike raw pg_dump) for a single
|
||||||
documentation for details. Note that format is
|
database. Or, when database name is "all" and
|
||||||
ignored when the database name is "all".
|
format is blank, dumps all databases to a single
|
||||||
|
file. But if a format is specified with an "all"
|
||||||
|
database name, dumps each database to a separate
|
||||||
|
file of that format, allowing more convenient
|
||||||
|
restores of individual databases. See the
|
||||||
|
pg_dump documentation for more about formats.
|
||||||
example: directory
|
example: directory
|
||||||
ssl_mode:
|
ssl_mode:
|
||||||
type: string
|
type: string
|
||||||
|
|
|
@ -24,7 +24,7 @@ SYSTEM_DATABASE_NAMES = ('information_schema', 'mysql', 'performance_schema', 's
|
||||||
|
|
||||||
def database_names_to_dump(database, extra_environment, log_prefix, dry_run_label):
|
def database_names_to_dump(database, extra_environment, log_prefix, dry_run_label):
|
||||||
'''
|
'''
|
||||||
Given a requested database name, return the corresponding sequence of database names to dump.
|
Given a requested database config, return the corresponding sequence of database names to dump.
|
||||||
In the case of "all", query for the names of databases on the configured host and return them,
|
In the case of "all", query for the names of databases on the configured host and return them,
|
||||||
excluding any system databases that will cause problems during restore.
|
excluding any system databases that will cause problems during restore.
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
|
import csv
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from borgmatic.execute import execute_command, execute_command_with_processes
|
from borgmatic.execute import (
|
||||||
|
execute_command,
|
||||||
|
execute_command_and_capture_output,
|
||||||
|
execute_command_with_processes,
|
||||||
|
)
|
||||||
from borgmatic.hooks import dump
|
from borgmatic.hooks import dump
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -34,6 +39,44 @@ def make_extra_environment(database):
|
||||||
return extra
|
return extra
|
||||||
|
|
||||||
|
|
||||||
|
EXCLUDED_DATABASE_NAMES = ('template0', 'template1')
|
||||||
|
|
||||||
|
|
||||||
|
def database_names_to_dump(database, extra_environment, log_prefix, dry_run_label):
|
||||||
|
'''
|
||||||
|
Given a requested database config, return the corresponding sequence of database names to dump.
|
||||||
|
In the case of "all" when a database format is given, query for the names of databases on the
|
||||||
|
configured host and return them. For "all" without a database format, just return a sequence
|
||||||
|
containing "all".
|
||||||
|
'''
|
||||||
|
requested_name = database['name']
|
||||||
|
|
||||||
|
if requested_name != 'all':
|
||||||
|
return (requested_name,)
|
||||||
|
if not database.get('format'):
|
||||||
|
return ('all',)
|
||||||
|
|
||||||
|
list_command = (
|
||||||
|
('psql', '--list', '--no-password', '--csv', '--tuples-only')
|
||||||
|
+ (('--host', database['hostname']) if 'hostname' in database else ())
|
||||||
|
+ (('--port', str(database['port'])) if 'port' in database else ())
|
||||||
|
+ (('--username', database['username']) if 'username' in database else ())
|
||||||
|
+ (tuple(database['options'].split(' ')) if 'options' in database else ())
|
||||||
|
)
|
||||||
|
logger.debug(
|
||||||
|
'{}: Querying for "all" PostgreSQL databases to dump{}'.format(log_prefix, dry_run_label)
|
||||||
|
)
|
||||||
|
list_output = execute_command_and_capture_output(
|
||||||
|
list_command, extra_environment=extra_environment
|
||||||
|
)
|
||||||
|
|
||||||
|
return tuple(
|
||||||
|
row[0]
|
||||||
|
for row in csv.reader(list_output.splitlines(), delimiter=',', quotechar='"')
|
||||||
|
if row[0] not in EXCLUDED_DATABASE_NAMES
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def dump_databases(databases, log_prefix, location_config, dry_run):
|
def dump_databases(databases, log_prefix, location_config, dry_run):
|
||||||
'''
|
'''
|
||||||
Dump the given PostgreSQL databases to a named pipe. The databases are supplied as a sequence of
|
Dump the given PostgreSQL databases to a named pipe. The databases are supplied as a sequence of
|
||||||
|
@ -43,6 +86,8 @@ def dump_databases(databases, log_prefix, location_config, dry_run):
|
||||||
|
|
||||||
Return a sequence of subprocess.Popen instances for the dump processes ready to spew to a named
|
Return a sequence of subprocess.Popen instances for the dump processes ready to spew to a named
|
||||||
pipe. But if this is a dry run, then don't actually dump anything and return an empty sequence.
|
pipe. But if this is a dry run, then don't actually dump anything and return an empty sequence.
|
||||||
|
|
||||||
|
Raise ValueError if the databases to dump cannot be determined.
|
||||||
'''
|
'''
|
||||||
dry_run_label = ' (dry run; not actually dumping anything)' if dry_run else ''
|
dry_run_label = ' (dry run; not actually dumping anything)' if dry_run else ''
|
||||||
processes = []
|
processes = []
|
||||||
|
@ -50,48 +95,59 @@ def dump_databases(databases, log_prefix, location_config, dry_run):
|
||||||
logger.info('{}: Dumping PostgreSQL databases{}'.format(log_prefix, dry_run_label))
|
logger.info('{}: Dumping PostgreSQL databases{}'.format(log_prefix, dry_run_label))
|
||||||
|
|
||||||
for database in databases:
|
for database in databases:
|
||||||
name = database['name']
|
|
||||||
dump_filename = dump.make_database_dump_filename(
|
|
||||||
make_dump_path(location_config), name, database.get('hostname')
|
|
||||||
)
|
|
||||||
all_databases = bool(name == 'all')
|
|
||||||
dump_format = database.get('format', 'custom')
|
|
||||||
default_dump_command = 'pg_dumpall' if all_databases else 'pg_dump'
|
|
||||||
dump_command = database.get('pg_dump_command') or default_dump_command
|
|
||||||
command = (
|
|
||||||
(dump_command, '--no-password', '--clean', '--if-exists',)
|
|
||||||
+ (('--host', database['hostname']) if 'hostname' in database else ())
|
|
||||||
+ (('--port', str(database['port'])) if 'port' in database else ())
|
|
||||||
+ (('--username', database['username']) if 'username' in database else ())
|
|
||||||
+ (() if all_databases else ('--format', dump_format))
|
|
||||||
+ (('--file', dump_filename) if dump_format == 'directory' else ())
|
|
||||||
+ (tuple(database['options'].split(' ')) if 'options' in database else ())
|
|
||||||
+ (() if all_databases else (name,))
|
|
||||||
# Use shell redirection rather than the --file flag to sidestep synchronization issues
|
|
||||||
# when pg_dump/pg_dumpall tries to write to a named pipe. But for the directory dump
|
|
||||||
# format in a particular, a named destination is required, and redirection doesn't work.
|
|
||||||
+ (('>', dump_filename) if dump_format != 'directory' else ())
|
|
||||||
)
|
|
||||||
extra_environment = make_extra_environment(database)
|
extra_environment = make_extra_environment(database)
|
||||||
|
dump_path = make_dump_path(location_config)
|
||||||
logger.debug(
|
dump_database_names = database_names_to_dump(
|
||||||
'{}: Dumping PostgreSQL database {} to {}{}'.format(
|
database, extra_environment, log_prefix, dry_run_label
|
||||||
log_prefix, name, dump_filename, dry_run_label
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if dry_run:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if dump_format == 'directory':
|
if not dump_database_names:
|
||||||
dump.create_parent_directory_for_dump(dump_filename)
|
raise ValueError('Cannot find any PostgreSQL databases to dump.')
|
||||||
else:
|
|
||||||
dump.create_named_pipe_for_dump(dump_filename)
|
|
||||||
|
|
||||||
processes.append(
|
for database_name in dump_database_names:
|
||||||
execute_command(
|
dump_format = database.get('format', None if database_name == 'all' else 'custom')
|
||||||
command, shell=True, extra_environment=extra_environment, run_to_completion=False
|
default_dump_command = 'pg_dumpall' if database_name == 'all' else 'pg_dump'
|
||||||
|
dump_command = database.get('pg_dump_command') or default_dump_command
|
||||||
|
dump_filename = dump.make_database_dump_filename(
|
||||||
|
dump_path, database_name, database.get('hostname')
|
||||||
|
)
|
||||||
|
|
||||||
|
command = (
|
||||||
|
(dump_command, '--no-password', '--clean', '--if-exists',)
|
||||||
|
+ (('--host', database['hostname']) if 'hostname' in database else ())
|
||||||
|
+ (('--port', str(database['port'])) if 'port' in database else ())
|
||||||
|
+ (('--username', database['username']) if 'username' in database else ())
|
||||||
|
+ (('--format', dump_format) if dump_format else ())
|
||||||
|
+ (('--file', dump_filename) if dump_format == 'directory' else ())
|
||||||
|
+ (tuple(database['options'].split(' ')) if 'options' in database else ())
|
||||||
|
+ (() if database_name == 'all' else (database_name,))
|
||||||
|
# Use shell redirection rather than the --file flag to sidestep synchronization issues
|
||||||
|
# when pg_dump/pg_dumpall tries to write to a named pipe. But for the directory dump
|
||||||
|
# format in a particular, a named destination is required, and redirection doesn't work.
|
||||||
|
+ (('>', dump_filename) if dump_format != 'directory' else ())
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
'{}: Dumping PostgreSQL database "{}" to {}{}'.format(
|
||||||
|
log_prefix, database_name, dump_filename, dry_run_label
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if dry_run:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if dump_format == 'directory':
|
||||||
|
dump.create_parent_directory_for_dump(dump_filename)
|
||||||
|
else:
|
||||||
|
dump.create_named_pipe_for_dump(dump_filename)
|
||||||
|
|
||||||
|
processes.append(
|
||||||
|
execute_command(
|
||||||
|
command,
|
||||||
|
shell=True,
|
||||||
|
extra_environment=extra_environment,
|
||||||
|
run_to_completion=False,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
return processes
|
return processes
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,9 @@ hooks:
|
||||||
options: "--ssl"
|
options: "--ssl"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### All databases
|
||||||
|
|
||||||
If you want to dump all databases on a host, use `all` for the database name:
|
If you want to dump all databases on a host, use `all` for the database name:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
@ -91,9 +94,30 @@ hooks:
|
||||||
Note that you may need to use a `username` of the `postgres` superuser for
|
Note that you may need to use a `username` of the `postgres` superuser for
|
||||||
this to work with PostgreSQL.
|
this to work with PostgreSQL.
|
||||||
|
|
||||||
If you would like to backup databases only and not source directories, you can
|
<span class="minilink minilink-addedin">New in version 1.7.6</span> With
|
||||||
specify an empty `source_directories` value (as it is a mandatory field prior
|
PostgreSQL and MySQL, you can optionally dump "all" databases to separate
|
||||||
to borgmatic 1.7.1):
|
files instead of one combined dump file, allowing more convenient restores of
|
||||||
|
individual databases. Enable this by specifying your desired database dump
|
||||||
|
`format`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
hooks:
|
||||||
|
postgresql_databases:
|
||||||
|
- name: all
|
||||||
|
format: custom
|
||||||
|
mysql_databases:
|
||||||
|
- name: all
|
||||||
|
format: sql
|
||||||
|
```
|
||||||
|
|
||||||
|
### No source directories
|
||||||
|
|
||||||
|
<span class="minilink minilink-addedin">New in version 1.7.1</span> If you
|
||||||
|
would like to backup databases only and not source directories, you can omit
|
||||||
|
`source_directories` entirely.
|
||||||
|
|
||||||
|
In older versions of borgmatic, instead specify an empty `source_directories`
|
||||||
|
value, as it is a mandatory option prior to version 1.7.1:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
location:
|
location:
|
||||||
|
@ -103,8 +127,7 @@ hooks:
|
||||||
- name: all
|
- name: all
|
||||||
```
|
```
|
||||||
|
|
||||||
<span class="minilink minilink-addedin">New in version 1.7.1</span> You can
|
|
||||||
omit `source_directories` entirely.
|
|
||||||
|
|
||||||
### External passwords
|
### External passwords
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,57 @@ from flexmock import flexmock
|
||||||
from borgmatic.hooks import postgresql as module
|
from borgmatic.hooks import postgresql as module
|
||||||
|
|
||||||
|
|
||||||
|
def test_database_names_to_dump_passes_through_individual_database_name():
|
||||||
|
database = {'name': 'foo'}
|
||||||
|
|
||||||
|
assert module.database_names_to_dump(database, flexmock(), flexmock(), flexmock()) == ('foo',)
|
||||||
|
|
||||||
|
|
||||||
|
def test_database_names_to_dump_passes_through_individual_database_name_with_format():
|
||||||
|
database = {'name': 'foo', 'format': 'custom'}
|
||||||
|
|
||||||
|
assert module.database_names_to_dump(database, flexmock(), flexmock(), flexmock()) == ('foo',)
|
||||||
|
|
||||||
|
|
||||||
|
def test_database_names_to_dump_passes_through_all_without_format():
|
||||||
|
database = {'name': 'all'}
|
||||||
|
|
||||||
|
assert module.database_names_to_dump(database, flexmock(), flexmock(), flexmock()) == ('all',)
|
||||||
|
|
||||||
|
|
||||||
|
def test_database_names_to_dump_with_all_and_format_lists_databases():
|
||||||
|
database = {'name': 'all', 'format': 'custom'}
|
||||||
|
flexmock(module).should_receive('execute_command_and_capture_output').and_return(
|
||||||
|
'foo,test,\nbar,test,"stuff and such"'
|
||||||
|
)
|
||||||
|
|
||||||
|
assert module.database_names_to_dump(database, flexmock(), flexmock(), flexmock()) == (
|
||||||
|
'foo',
|
||||||
|
'bar',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_database_names_to_dump_with_all_and_format_excludes_particular_databases():
|
||||||
|
database = {'name': 'all', 'format': 'custom'}
|
||||||
|
flexmock(module).should_receive('execute_command_and_capture_output').and_return(
|
||||||
|
'foo,test,\ntemplate0,test,blah'
|
||||||
|
)
|
||||||
|
|
||||||
|
assert module.database_names_to_dump(database, flexmock(), flexmock(), flexmock()) == ('foo',)
|
||||||
|
|
||||||
|
|
||||||
def test_dump_databases_runs_pg_dump_for_each_database():
|
def test_dump_databases_runs_pg_dump_for_each_database():
|
||||||
databases = [{'name': 'foo'}, {'name': 'bar'}]
|
databases = [{'name': 'foo'}, {'name': 'bar'}]
|
||||||
processes = [flexmock(), flexmock()]
|
processes = [flexmock(), flexmock()]
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||||
|
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',)).and_return(
|
||||||
|
('bar',)
|
||||||
|
)
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
||||||
'databases/localhost/foo'
|
'databases/localhost/foo'
|
||||||
).and_return('databases/localhost/bar')
|
).and_return('databases/localhost/bar')
|
||||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
|
|
||||||
for name, process in zip(('foo', 'bar'), processes):
|
for name, process in zip(('foo', 'bar'), processes):
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
|
@ -37,14 +79,27 @@ def test_dump_databases_runs_pg_dump_for_each_database():
|
||||||
assert module.dump_databases(databases, 'test.yaml', {}, dry_run=False) == processes
|
assert module.dump_databases(databases, 'test.yaml', {}, dry_run=False) == processes
|
||||||
|
|
||||||
|
|
||||||
|
def test_dump_databases_runs_raises_when_no_database_names_to_dump():
|
||||||
|
databases = [{'name': 'foo'}, {'name': 'bar'}]
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
|
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||||
|
flexmock(module).should_receive('database_names_to_dump').and_return(())
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
module.dump_databases(databases, 'test.yaml', {}, dry_run=False)
|
||||||
|
|
||||||
|
|
||||||
def test_dump_databases_with_dry_run_skips_pg_dump():
|
def test_dump_databases_with_dry_run_skips_pg_dump():
|
||||||
databases = [{'name': 'foo'}, {'name': 'bar'}]
|
databases = [{'name': 'foo'}, {'name': 'bar'}]
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||||
|
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',)).and_return(
|
||||||
|
('bar',)
|
||||||
|
)
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
||||||
'databases/localhost/foo'
|
'databases/localhost/foo'
|
||||||
).and_return('databases/localhost/bar')
|
).and_return('databases/localhost/bar')
|
||||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump').never()
|
flexmock(module.dump).should_receive('create_named_pipe_for_dump').never()
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
flexmock(module).should_receive('execute_command').never()
|
flexmock(module).should_receive('execute_command').never()
|
||||||
|
|
||||||
assert module.dump_databases(databases, 'test.yaml', {}, dry_run=True) == []
|
assert module.dump_databases(databases, 'test.yaml', {}, dry_run=True) == []
|
||||||
|
@ -53,12 +108,13 @@ def test_dump_databases_with_dry_run_skips_pg_dump():
|
||||||
def test_dump_databases_runs_pg_dump_with_hostname_and_port():
|
def test_dump_databases_runs_pg_dump_with_hostname_and_port():
|
||||||
databases = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
|
databases = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
|
||||||
process = flexmock()
|
process = flexmock()
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||||
|
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',))
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
||||||
'databases/database.example.org/foo'
|
'databases/database.example.org/foo'
|
||||||
)
|
)
|
||||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
|
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
(
|
(
|
||||||
|
@ -87,14 +143,15 @@ def test_dump_databases_runs_pg_dump_with_hostname_and_port():
|
||||||
def test_dump_databases_runs_pg_dump_with_username_and_password():
|
def test_dump_databases_runs_pg_dump_with_username_and_password():
|
||||||
databases = [{'name': 'foo', 'username': 'postgres', 'password': 'trustsome1'}]
|
databases = [{'name': 'foo', 'username': 'postgres', 'password': 'trustsome1'}]
|
||||||
process = flexmock()
|
process = flexmock()
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return(
|
||||||
|
{'PGPASSWORD': 'trustsome1', 'PGSSLMODE': 'disable'}
|
||||||
|
)
|
||||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||||
|
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',))
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
||||||
'databases/localhost/foo'
|
'databases/localhost/foo'
|
||||||
)
|
)
|
||||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return(
|
|
||||||
{'PGPASSWORD': 'trustsome1', 'PGSSLMODE': 'disable'}
|
|
||||||
)
|
|
||||||
|
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
(
|
(
|
||||||
|
@ -144,13 +201,14 @@ def test_make_extra_environment_maps_options_to_environment():
|
||||||
def test_dump_databases_runs_pg_dump_with_directory_format():
|
def test_dump_databases_runs_pg_dump_with_directory_format():
|
||||||
databases = [{'name': 'foo', 'format': 'directory'}]
|
databases = [{'name': 'foo', 'format': 'directory'}]
|
||||||
process = flexmock()
|
process = flexmock()
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||||
|
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',))
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
||||||
'databases/localhost/foo'
|
'databases/localhost/foo'
|
||||||
)
|
)
|
||||||
flexmock(module.dump).should_receive('create_parent_directory_for_dump')
|
flexmock(module.dump).should_receive('create_parent_directory_for_dump')
|
||||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump').never()
|
flexmock(module.dump).should_receive('create_named_pipe_for_dump').never()
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
|
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
(
|
(
|
||||||
|
@ -175,12 +233,13 @@ def test_dump_databases_runs_pg_dump_with_directory_format():
|
||||||
def test_dump_databases_runs_pg_dump_with_options():
|
def test_dump_databases_runs_pg_dump_with_options():
|
||||||
databases = [{'name': 'foo', 'options': '--stuff=such'}]
|
databases = [{'name': 'foo', 'options': '--stuff=such'}]
|
||||||
process = flexmock()
|
process = flexmock()
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||||
|
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',))
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
||||||
'databases/localhost/foo'
|
'databases/localhost/foo'
|
||||||
)
|
)
|
||||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
|
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
(
|
(
|
||||||
|
@ -206,12 +265,13 @@ def test_dump_databases_runs_pg_dump_with_options():
|
||||||
def test_dump_databases_runs_pg_dumpall_for_all_databases():
|
def test_dump_databases_runs_pg_dumpall_for_all_databases():
|
||||||
databases = [{'name': 'all'}]
|
databases = [{'name': 'all'}]
|
||||||
process = flexmock()
|
process = flexmock()
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||||
|
flexmock(module).should_receive('database_names_to_dump').and_return(('all',))
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
||||||
'databases/localhost/all'
|
'databases/localhost/all'
|
||||||
)
|
)
|
||||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
|
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('pg_dumpall', '--no-password', '--clean', '--if-exists', '>', 'databases/localhost/all'),
|
('pg_dumpall', '--no-password', '--clean', '--if-exists', '>', 'databases/localhost/all'),
|
||||||
|
@ -226,12 +286,13 @@ def test_dump_databases_runs_pg_dumpall_for_all_databases():
|
||||||
def test_dump_databases_runs_non_default_pg_dump():
|
def test_dump_databases_runs_non_default_pg_dump():
|
||||||
databases = [{'name': 'foo', 'pg_dump_command': 'special_pg_dump'}]
|
databases = [{'name': 'foo', 'pg_dump_command': 'special_pg_dump'}]
|
||||||
process = flexmock()
|
process = flexmock()
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||||
|
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',))
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
||||||
'databases/localhost/foo'
|
'databases/localhost/foo'
|
||||||
)
|
)
|
||||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
|
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
(
|
(
|
||||||
|
@ -257,9 +318,9 @@ def test_restore_database_dump_runs_pg_restore():
|
||||||
database_config = [{'name': 'foo'}]
|
database_config = [{'name': 'foo'}]
|
||||||
extract_process = flexmock(stdout=flexmock())
|
extract_process = flexmock(stdout=flexmock())
|
||||||
|
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path')
|
flexmock(module).should_receive('make_dump_path')
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename')
|
flexmock(module.dump).should_receive('make_database_dump_filename')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
(
|
(
|
||||||
'pg_restore',
|
'pg_restore',
|
||||||
|
@ -288,9 +349,9 @@ def test_restore_database_dump_runs_pg_restore():
|
||||||
def test_restore_database_dump_errors_on_multiple_database_config():
|
def test_restore_database_dump_errors_on_multiple_database_config():
|
||||||
database_config = [{'name': 'foo'}, {'name': 'bar'}]
|
database_config = [{'name': 'foo'}, {'name': 'bar'}]
|
||||||
|
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path')
|
flexmock(module).should_receive('make_dump_path')
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename')
|
flexmock(module.dump).should_receive('make_database_dump_filename')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
flexmock(module).should_receive('execute_command_with_processes').never()
|
flexmock(module).should_receive('execute_command_with_processes').never()
|
||||||
flexmock(module).should_receive('execute_command').never()
|
flexmock(module).should_receive('execute_command').never()
|
||||||
|
|
||||||
|
@ -304,9 +365,9 @@ def test_restore_database_dump_runs_pg_restore_with_hostname_and_port():
|
||||||
database_config = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
|
database_config = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
|
||||||
extract_process = flexmock(stdout=flexmock())
|
extract_process = flexmock(stdout=flexmock())
|
||||||
|
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path')
|
flexmock(module).should_receive('make_dump_path')
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename')
|
flexmock(module.dump).should_receive('make_database_dump_filename')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
(
|
(
|
||||||
'pg_restore',
|
'pg_restore',
|
||||||
|
@ -352,11 +413,11 @@ def test_restore_database_dump_runs_pg_restore_with_username_and_password():
|
||||||
database_config = [{'name': 'foo', 'username': 'postgres', 'password': 'trustsome1'}]
|
database_config = [{'name': 'foo', 'username': 'postgres', 'password': 'trustsome1'}]
|
||||||
extract_process = flexmock(stdout=flexmock())
|
extract_process = flexmock(stdout=flexmock())
|
||||||
|
|
||||||
flexmock(module).should_receive('make_dump_path')
|
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename')
|
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return(
|
flexmock(module).should_receive('make_extra_environment').and_return(
|
||||||
{'PGPASSWORD': 'trustsome1', 'PGSSLMODE': 'disable'}
|
{'PGPASSWORD': 'trustsome1', 'PGSSLMODE': 'disable'}
|
||||||
)
|
)
|
||||||
|
flexmock(module).should_receive('make_dump_path')
|
||||||
|
flexmock(module.dump).should_receive('make_database_dump_filename')
|
||||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
(
|
(
|
||||||
'pg_restore',
|
'pg_restore',
|
||||||
|
@ -398,9 +459,9 @@ def test_restore_database_dump_runs_psql_for_all_database_dump():
|
||||||
database_config = [{'name': 'all'}]
|
database_config = [{'name': 'all'}]
|
||||||
extract_process = flexmock(stdout=flexmock())
|
extract_process = flexmock(stdout=flexmock())
|
||||||
|
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path')
|
flexmock(module).should_receive('make_dump_path')
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename')
|
flexmock(module.dump).should_receive('make_database_dump_filename')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
('psql', '--no-password'),
|
('psql', '--no-password'),
|
||||||
processes=[extract_process],
|
processes=[extract_process],
|
||||||
|
@ -424,9 +485,9 @@ def test_restore_database_dump_runs_non_default_pg_restore_and_psql():
|
||||||
]
|
]
|
||||||
extract_process = flexmock(stdout=flexmock())
|
extract_process = flexmock(stdout=flexmock())
|
||||||
|
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path')
|
flexmock(module).should_receive('make_dump_path')
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename')
|
flexmock(module.dump).should_receive('make_database_dump_filename')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
(
|
(
|
||||||
'special_pg_restore',
|
'special_pg_restore',
|
||||||
|
@ -455,9 +516,9 @@ def test_restore_database_dump_runs_non_default_pg_restore_and_psql():
|
||||||
def test_restore_database_dump_with_dry_run_skips_restore():
|
def test_restore_database_dump_with_dry_run_skips_restore():
|
||||||
database_config = [{'name': 'foo'}]
|
database_config = [{'name': 'foo'}]
|
||||||
|
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path')
|
flexmock(module).should_receive('make_dump_path')
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename')
|
flexmock(module.dump).should_receive('make_database_dump_filename')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
flexmock(module).should_receive('execute_command_with_processes').never()
|
flexmock(module).should_receive('execute_command_with_processes').never()
|
||||||
|
|
||||||
module.restore_database_dump(
|
module.restore_database_dump(
|
||||||
|
@ -468,9 +529,9 @@ def test_restore_database_dump_with_dry_run_skips_restore():
|
||||||
def test_restore_database_dump_without_extract_process_restores_from_disk():
|
def test_restore_database_dump_without_extract_process_restores_from_disk():
|
||||||
database_config = [{'name': 'foo'}]
|
database_config = [{'name': 'foo'}]
|
||||||
|
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
flexmock(module).should_receive('make_dump_path')
|
flexmock(module).should_receive('make_dump_path')
|
||||||
flexmock(module.dump).should_receive('make_database_dump_filename').and_return('/dump/path')
|
flexmock(module.dump).should_receive('make_database_dump_filename').and_return('/dump/path')
|
||||||
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
|
||||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
(
|
(
|
||||||
'pg_restore',
|
'pg_restore',
|
||||||
|
|
Loading…
Reference in a new issue