Selaa lähdekoodia

Optionally change the internal database dump path via "borgmatic_source_directory" option in location configuration section (#259).

Dan Helfman 5 vuotta sitten
vanhempi
sitoutus
8660af745e

+ 4 - 0
NEWS

@@ -1,3 +1,7 @@
+1.4.19
+ * #259: Optionally change the internal database dump path via "borgmatic_source_directory" option
+   in location configuration section.
+
 1.4.18
  * Fix "--repository" flag to accept relative paths.
  * Fix "borgmatic umount" so it only runs Borg once instead of once per repository / configuration

+ 9 - 5
borgmatic/borg/create.py

@@ -104,16 +104,19 @@ def _make_exclude_flags(location_config, exclude_filename=None):
     )
 
 
-BORGMATIC_SOURCE_DIRECTORY = '~/.borgmatic'
+DEFAULT_BORGMATIC_SOURCE_DIRECTORY = '~/.borgmatic'
 
 
-def borgmatic_source_directories():
+def borgmatic_source_directories(borgmatic_source_directory):
     '''
     Return a list of borgmatic-specific source directories used for state like database backups.
     '''
+    if not borgmatic_source_directory:
+        borgmatic_source_directory = DEFAULT_BORGMATIC_SOURCE_DIRECTORY
+
     return (
-        [BORGMATIC_SOURCE_DIRECTORY]
-        if os.path.exists(os.path.expanduser(BORGMATIC_SOURCE_DIRECTORY))
+        [borgmatic_source_directory]
+        if os.path.exists(os.path.expanduser(borgmatic_source_directory))
         else []
     )
 
@@ -134,7 +137,8 @@ def create_archive(
     storage config dict, create a Borg archive and return Borg's JSON output (if any).
     '''
     sources = _expand_directories(
-        location_config['source_directories'] + borgmatic_source_directories()
+        location_config['source_directories']
+        + borgmatic_source_directories(location_config.get('borgmatic_source_directory'))
     )
 
     pattern_file = _write_pattern_file(location_config.get('patterns'))

+ 5 - 0
borgmatic/commands/borgmatic.py

@@ -75,6 +75,7 @@ def run_configuration(config_filename, config, arguments):
                 hooks,
                 config_filename,
                 dump.DATABASE_HOOK_NAMES,
+                location,
                 global_arguments.dry_run,
             )
         except (OSError, CalledProcessError) as error:
@@ -111,6 +112,7 @@ def run_configuration(config_filename, config, arguments):
                 hooks,
                 config_filename,
                 dump.DATABASE_HOOK_NAMES,
+                location,
                 global_arguments.dry_run,
             )
             command.execute_hook(
@@ -294,6 +296,7 @@ def run_actions(
                 hooks,
                 repository,
                 dump.DATABASE_HOOK_NAMES,
+                location,
                 restore_names,
             )
 
@@ -325,6 +328,7 @@ def run_actions(
                 restore_databases,
                 repository,
                 dump.DATABASE_HOOK_NAMES,
+                location,
                 global_arguments.dry_run,
             )
             dispatch.call_hooks(
@@ -332,6 +336,7 @@ def run_actions(
                 restore_databases,
                 repository,
                 dump.DATABASE_HOOK_NAMES,
+                location,
                 global_arguments.dry_run,
             )
     if 'list' in arguments:

+ 8 - 0
borgmatic/config/schema.yaml

@@ -137,6 +137,14 @@ map:
                 desc: |
                     Exclude files with the NODUMP flag. Defaults to false.
                 example: true
+            borgmatic_source_directory:
+                type: str
+                desc: |
+                    Path for additional source files used for temporary internal state like
+                    borgmatic database dumps. Note that changing this path prevents "borgmatic
+                    restore" from finding any database dumps created before the change. Defaults
+                    to ~/.borgmatic
+                example: /tmp/borgmatic
     storage:
         desc: |
             Repository storage options. See

+ 13 - 0
borgmatic/hooks/dump.py

@@ -2,11 +2,24 @@ import glob
 import logging
 import os
 
+from borgmatic.borg.create import DEFAULT_BORGMATIC_SOURCE_DIRECTORY
+
 logger = logging.getLogger(__name__)
 
 DATABASE_HOOK_NAMES = ('postgresql_databases', 'mysql_databases')
 
 
+def make_database_dump_path(borgmatic_source_directory, database_hook_name):
+    '''
+    Given a borgmatic source directory (or None) and a database hook name, construct a database dump
+    path.
+    '''
+    if not borgmatic_source_directory:
+        borgmatic_source_directory = DEFAULT_BORGMATIC_SOURCE_DIRECTORY
+
+    return os.path.join(borgmatic_source_directory, database_hook_name)
+
+
 def make_database_dump_filename(dump_path, name, hostname=None):
     '''
     Based on the given dump directory path, database name, and hostname, return a filename to use

+ 32 - 15
borgmatic/hooks/mysql.py

@@ -4,15 +4,24 @@ import os
 from borgmatic.execute import execute_command
 from borgmatic.hooks import dump
 
-DUMP_PATH = '~/.borgmatic/mysql_databases'
 logger = logging.getLogger(__name__)
 
 
-def dump_databases(databases, log_prefix, dry_run):
+def make_dump_path(location_config):  # pragma: no cover
+    '''
+    Make the dump path from the given location configuration and the name of this hook.
+    '''
+    return dump.make_database_dump_path(
+        location_config.get('borgmatic_source_directory'), 'mysql_databases'
+    )
+
+
+def dump_databases(databases, log_prefix, location_config, dry_run):
     '''
     Dump the given MySQL/MariaDB databases to disk. The databases are supplied as a sequence of
     dicts, one dict describing each database as per the configuration schema. Use the given log
-    prefix in any log entries. If this is a dry run, then don't actually dump anything.
+    prefix in any log entries. Use the given location configuration dict to construct the
+    destination path. If this is a dry run, then don't actually dump anything.
     '''
     dry_run_label = ' (dry run; not actually dumping anything)' if dry_run else ''
 
@@ -20,7 +29,9 @@ def dump_databases(databases, log_prefix, dry_run):
 
     for database in databases:
         name = database['name']
-        dump_filename = dump.make_database_dump_filename(DUMP_PATH, name, database.get('hostname'))
+        dump_filename = dump.make_database_dump_filename(
+            make_dump_path(location_config), name, database.get('hostname')
+        )
         command = (
             ('mysqldump', '--add-drop-database')
             + (('--host', database['hostname']) if 'hostname' in database else ())
@@ -44,37 +55,43 @@ def dump_databases(databases, log_prefix, dry_run):
             )
 
 
-def remove_database_dumps(databases, log_prefix, dry_run):  # pragma: no cover
+def remove_database_dumps(databases, log_prefix, location_config, dry_run):  # pragma: no cover
     '''
     Remove the database dumps for the given databases. The databases are supplied as a sequence of
     dicts, one dict describing each database as per the configuration schema. Use the log prefix in
-    any log entries. If this is a dry run, then don't actually remove anything.
+    any log entries. Use the given location configuration dict to construct the destination path. If
+    this is a dry run, then don't actually remove anything.
     '''
-    dump.remove_database_dumps(DUMP_PATH, databases, 'MySQL', log_prefix, dry_run)
+    dump.remove_database_dumps(
+        make_dump_path(location_config), databases, 'MySQL', log_prefix, dry_run
+    )
 
 
-def make_database_dump_patterns(databases, log_prefix, names):
+def make_database_dump_patterns(databases, log_prefix, location_config, names):
     '''
-    Given a sequence of configurations dicts, a prefix to log with, and a sequence of database
-    names to match, return the corresponding glob patterns to match the database dumps in an
-    archive. An empty sequence of names indicates that the patterns should match all dumps.
+    Given a sequence of configurations dicts, a prefix to log with, a location configuration dict,
+    and a sequence of database names to match, return the corresponding glob patterns to match the
+    database dumps in an archive. An empty sequence of names indicates that the patterns should
+    match all dumps.
     '''
     return [
-        dump.make_database_dump_filename(DUMP_PATH, name, hostname='*') for name in (names or ['*'])
+        dump.make_database_dump_filename(make_dump_path(location_config), name, hostname='*')
+        for name in (names or ['*'])
     ]
 
 
-def restore_database_dumps(databases, log_prefix, dry_run):
+def restore_database_dumps(databases, log_prefix, location_config, dry_run):
     '''
     Restore the given MySQL/MariaDB databases from disk. The databases are supplied as a sequence of
     dicts, one dict describing each database as per the configuration schema. Use the given log
-    prefix in any log entries. If this is a dry run, then don't actually restore anything.
+    prefix in any log entries. Use the given location configuration dict to construct the
+    destination path. If this is a dry run, then don't actually restore anything.
     '''
     dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else ''
 
     for database in databases:
         dump_filename = dump.make_database_dump_filename(
-            DUMP_PATH, database['name'], database.get('hostname')
+            make_dump_path(location_config), database['name'], database.get('hostname')
         )
         restore_command = (
             ('mysql', '--batch')

+ 32 - 15
borgmatic/hooks/postgresql.py

@@ -4,15 +4,24 @@ import os
 from borgmatic.execute import execute_command
 from borgmatic.hooks import dump
 
-DUMP_PATH = '~/.borgmatic/postgresql_databases'
 logger = logging.getLogger(__name__)
 
 
-def dump_databases(databases, log_prefix, dry_run):
+def make_dump_path(location_config):  # pragma: no cover
+    '''
+    Make the dump path from the given location configuration and the name of this hook.
+    '''
+    return dump.make_database_dump_path(
+        location_config.get('borgmatic_source_directory'), 'postgresql_databases'
+    )
+
+
+def dump_databases(databases, log_prefix, location_config, dry_run):
     '''
     Dump the given PostgreSQL databases to disk. The databases are supplied as a sequence of dicts,
     one dict describing each database as per the configuration schema. Use the given log prefix in
-    any log entries. If this is a dry run, then don't actually dump anything.
+    any log entries. Use the given location configuration dict to construct the destination path. If
+    this is a dry run, then don't actually dump anything.
     '''
     dry_run_label = ' (dry run; not actually dumping anything)' if dry_run else ''
 
@@ -20,7 +29,9 @@ def dump_databases(databases, log_prefix, dry_run):
 
     for database in databases:
         name = database['name']
-        dump_filename = dump.make_database_dump_filename(DUMP_PATH, name, database.get('hostname'))
+        dump_filename = dump.make_database_dump_filename(
+            make_dump_path(location_config), name, database.get('hostname')
+        )
         all_databases = bool(name == 'all')
         command = (
             ('pg_dumpall' if all_databases else 'pg_dump', '--no-password', '--clean')
@@ -44,37 +55,43 @@ def dump_databases(databases, log_prefix, dry_run):
             execute_command(command, extra_environment=extra_environment)
 
 
-def remove_database_dumps(databases, log_prefix, dry_run):  # pragma: no cover
+def remove_database_dumps(databases, log_prefix, location_config, dry_run):  # pragma: no cover
     '''
     Remove the database dumps for the given databases. The databases are supplied as a sequence of
     dicts, one dict describing each database as per the configuration schema. Use the log prefix in
-    any log entries. If this is a dry run, then don't actually remove anything.
+    any log entries. Use the given location configuration dict to construct the destination path. If
+    this is a dry run, then don't actually remove anything.
     '''
-    dump.remove_database_dumps(DUMP_PATH, databases, 'PostgreSQL', log_prefix, dry_run)
+    dump.remove_database_dumps(
+        make_dump_path(location_config), databases, 'PostgreSQL', log_prefix, dry_run
+    )
 
 
-def make_database_dump_patterns(databases, log_prefix, names):
+def make_database_dump_patterns(databases, log_prefix, location_config, names):
     '''
-    Given a sequence of configurations dicts, a prefix to log with, and a sequence of database
-    names to match, return the corresponding glob patterns to match the database dumps in an
-    archive. An empty sequence of names indicates that the patterns should match all dumps.
+    Given a sequence of configurations dicts, a prefix to log with, a location configuration dict,
+    and a sequence of database names to match, return the corresponding glob patterns to match the
+    database dumps in an archive. An empty sequence of names indicates that the patterns should
+    match all dumps.
     '''
     return [
-        dump.make_database_dump_filename(DUMP_PATH, name, hostname='*') for name in (names or ['*'])
+        dump.make_database_dump_filename(make_dump_path(location_config), name, hostname='*')
+        for name in (names or ['*'])
     ]
 
 
-def restore_database_dumps(databases, log_prefix, dry_run):
+def restore_database_dumps(databases, log_prefix, location_config, dry_run):
     '''
     Restore the given PostgreSQL databases from disk. The databases are supplied as a sequence of
     dicts, one dict describing each database as per the configuration schema. Use the given log
-    prefix in any log entries. If this is a dry run, then don't actually restore anything.
+    prefix in any log entries. Use the given location configuration dict to construct the
+    destination path. If this is a dry run, then don't actually restore anything.
     '''
     dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else ''
 
     for database in databases:
         dump_filename = dump.make_database_dump_filename(
-            DUMP_PATH, database['name'], database.get('hostname')
+            make_dump_path(location_config), database['name'], database.get('hostname')
         )
         restore_command = (
             ('pg_restore', '--no-password', '--clean', '--if-exists', '--exit-on-error')

+ 6 - 2
docs/how-to/backup-your-databases.md

@@ -23,8 +23,12 @@ hooks:
 ```
 
 Prior to each backup, borgmatic dumps each configured database to a file
-(located in `~/.borgmatic/`) and includes it in the backup. After the backup
-completes, borgmatic removes the database dump files to recover disk space.
+and includes it in the backup. After the backup completes, borgmatic removes
+the database dump files to recover disk space.
+
+borgmatic creates these temporary dump files in `~/.borgmatic` by default. To
+customize this path, set the `borgmatic_source_directory` option in the
+`location` section of borgmatic's configuration.
 
 Here's a more involved example that connects to remote databases:
 

+ 1 - 1
setup.py

@@ -1,6 +1,6 @@
 from setuptools import find_packages, setup
 
-VERSION = '1.4.18'
+VERSION = '1.4.19'
 
 
 setup(

+ 9 - 2
tests/unit/borg/test_create.py

@@ -184,14 +184,21 @@ def test_borgmatic_source_directories_set_when_directory_exists():
     flexmock(module.os.path).should_receive('exists').and_return(True)
     flexmock(module.os.path).should_receive('expanduser')
 
-    assert module.borgmatic_source_directories() == [module.BORGMATIC_SOURCE_DIRECTORY]
+    assert module.borgmatic_source_directories('/tmp') == ['/tmp']
 
 
 def test_borgmatic_source_directories_empty_when_directory_does_not_exist():
     flexmock(module.os.path).should_receive('exists').and_return(False)
     flexmock(module.os.path).should_receive('expanduser')
 
-    assert module.borgmatic_source_directories() == []
+    assert module.borgmatic_source_directories('/tmp') == []
+
+
+def test_borgmatic_source_directories_defaults_when_directory_not_given():
+    flexmock(module.os.path).should_receive('exists').and_return(True)
+    flexmock(module.os.path).should_receive('expanduser')
+
+    assert module.borgmatic_source_directories(None) == [module.DEFAULT_BORGMATIC_SOURCE_DIRECTORY]
 
 
 DEFAULT_ARCHIVE_NAME = '{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f}'

+ 8 - 0
tests/unit/hooks/test_dump.py

@@ -4,6 +4,14 @@ from flexmock import flexmock
 from borgmatic.hooks import dump as module
 
 
+def test_make_database_dump_path_joins_arguments():
+    assert module.make_database_dump_path('/tmp', 'super_databases') == '/tmp/super_databases'
+
+
+def test_make_database_dump_path_defaults_without_source_directory():
+    assert module.make_database_dump_path(None, 'super_databases') == '~/.borgmatic/super_databases'
+
+
 def test_make_database_dump_filename_uses_name_and_hostname():
     flexmock(module.os.path).should_receive('expanduser').and_return('databases')
 

+ 23 - 12
tests/unit/hooks/test_mysql.py

@@ -8,6 +8,7 @@ from borgmatic.hooks import mysql as module
 def test_dump_databases_runs_mysqldump_for_each_database():
     databases = [{'name': 'foo'}, {'name': 'bar'}]
     output_file = flexmock()
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     ).and_return('databases/localhost/bar')
@@ -21,23 +22,25 @@ def test_dump_databases_runs_mysqldump_for_each_database():
             extra_environment=None,
         ).once()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=False)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_dump_databases_with_dry_run_skips_mysqldump():
     databases = [{'name': 'foo'}, {'name': 'bar'}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     ).and_return('databases/localhost/bar')
     flexmock(module.os).should_receive('makedirs').never()
     flexmock(module).should_receive('execute_command').never()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=True)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=True)
 
 
 def test_dump_databases_runs_mysqldump_with_hostname_and_port():
     databases = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
     output_file = flexmock()
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/database.example.org/foo'
     )
@@ -61,12 +64,13 @@ def test_dump_databases_runs_mysqldump_with_hostname_and_port():
         extra_environment=None,
     ).once()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=False)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_dump_databases_runs_mysqldump_with_username_and_password():
     databases = [{'name': 'foo', 'username': 'root', 'password': 'trustsome1'}]
     output_file = flexmock()
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     )
@@ -79,12 +83,13 @@ def test_dump_databases_runs_mysqldump_with_username_and_password():
         extra_environment={'MYSQL_PWD': 'trustsome1'},
     ).once()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=False)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_dump_databases_runs_mysqldump_with_options():
     databases = [{'name': 'foo', 'options': '--stuff=such'}]
     output_file = flexmock()
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     )
@@ -97,12 +102,13 @@ def test_dump_databases_runs_mysqldump_with_options():
         extra_environment=None,
     ).once()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=False)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_dump_databases_runs_mysqldump_for_all_databases():
     databases = [{'name': 'all'}]
     output_file = flexmock()
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/all'
     )
@@ -115,30 +121,33 @@ def test_dump_databases_runs_mysqldump_for_all_databases():
         extra_environment=None,
     ).once()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=False)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_make_database_dump_patterns_converts_names_to_glob_paths():
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/*/foo'
     ).and_return('databases/*/bar')
 
-    assert module.make_database_dump_patterns(flexmock(), flexmock(), ('foo', 'bar')) == [
+    assert module.make_database_dump_patterns(flexmock(), flexmock(), {}, ('foo', 'bar')) == [
         'databases/*/foo',
         'databases/*/bar',
     ]
 
 
 def test_make_database_dump_patterns_treats_empty_names_as_matching_all_databases():
+    flexmock(module).should_receive('make_dump_path').and_return('/dump/path')
     flexmock(module.dump).should_receive('make_database_dump_filename').with_args(
-        module.DUMP_PATH, '*', '*'
+        '/dump/path', '*', '*'
     ).and_return('databases/*/*')
 
-    assert module.make_database_dump_patterns(flexmock(), flexmock(), ()) == ['databases/*/*']
+    assert module.make_database_dump_patterns(flexmock(), flexmock(), {}, ()) == ['databases/*/*']
 
 
 def test_restore_database_dumps_restores_each_database():
     databases = [{'name': 'foo'}, {'name': 'bar'}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     ).and_return('databases/localhost/bar')
@@ -153,11 +162,12 @@ def test_restore_database_dumps_restores_each_database():
             ('mysql', '--batch'), input_file=input_file, extra_environment=None
         ).once()
 
-    module.restore_database_dumps(databases, 'test.yaml', dry_run=False)
+    module.restore_database_dumps(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_restore_database_dumps_runs_mysql_with_hostname_and_port():
     databases = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     )
@@ -182,11 +192,12 @@ def test_restore_database_dumps_runs_mysql_with_hostname_and_port():
         extra_environment=None,
     ).once()
 
-    module.restore_database_dumps(databases, 'test.yaml', dry_run=False)
+    module.restore_database_dumps(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_restore_database_dumps_runs_mysql_with_username_and_password():
     databases = [{'name': 'foo', 'username': 'root', 'password': 'trustsome1'}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     )
@@ -202,4 +213,4 @@ def test_restore_database_dumps_runs_mysql_with_username_and_password():
         extra_environment={'MYSQL_PWD': 'trustsome1'},
     ).once()
 
-    module.restore_database_dumps(databases, 'test.yaml', dry_run=False)
+    module.restore_database_dumps(databases, 'test.yaml', {}, dry_run=False)

+ 25 - 13
tests/unit/hooks/test_postgresql.py

@@ -5,6 +5,7 @@ from borgmatic.hooks import postgresql as module
 
 def test_dump_databases_runs_pg_dump_for_each_database():
     databases = [{'name': 'foo'}, {'name': 'bar'}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     ).and_return('databases/localhost/bar')
@@ -25,22 +26,24 @@ def test_dump_databases_runs_pg_dump_for_each_database():
             extra_environment=None,
         ).once()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=False)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_dump_databases_with_dry_run_skips_pg_dump():
     databases = [{'name': 'foo'}, {'name': 'bar'}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     ).and_return('databases/localhost/bar')
     flexmock(module.os).should_receive('makedirs').never()
     flexmock(module).should_receive('execute_command').never()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=True)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=True)
 
 
 def test_dump_databases_runs_pg_dump_with_hostname_and_port():
     databases = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/database.example.org/foo'
     )
@@ -64,11 +67,12 @@ def test_dump_databases_runs_pg_dump_with_hostname_and_port():
         extra_environment=None,
     ).once()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=False)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_dump_databases_runs_pg_dump_with_username_and_password():
     databases = [{'name': 'foo', 'username': 'postgres', 'password': 'trustsome1'}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     )
@@ -90,11 +94,12 @@ def test_dump_databases_runs_pg_dump_with_username_and_password():
         extra_environment={'PGPASSWORD': 'trustsome1'},
     ).once()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=False)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_dump_databases_runs_pg_dump_with_format():
     databases = [{'name': 'foo', 'format': 'tar'}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     )
@@ -114,11 +119,12 @@ def test_dump_databases_runs_pg_dump_with_format():
         extra_environment=None,
     ).once()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=False)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_dump_databases_runs_pg_dump_with_options():
     databases = [{'name': 'foo', 'options': '--stuff=such'}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     )
@@ -139,11 +145,12 @@ def test_dump_databases_runs_pg_dump_with_options():
         extra_environment=None,
     ).once()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=False)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_dump_databases_runs_pg_dumpall_for_all_databases():
     databases = [{'name': 'all'}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/all'
     )
@@ -154,30 +161,33 @@ def test_dump_databases_runs_pg_dumpall_for_all_databases():
         extra_environment=None,
     ).once()
 
-    module.dump_databases(databases, 'test.yaml', dry_run=False)
+    module.dump_databases(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_make_database_dump_patterns_converts_names_to_glob_paths():
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/*/foo'
     ).and_return('databases/*/bar')
 
-    assert module.make_database_dump_patterns(flexmock(), flexmock(), ('foo', 'bar')) == [
+    assert module.make_database_dump_patterns(flexmock(), flexmock(), {}, ('foo', 'bar')) == [
         'databases/*/foo',
         'databases/*/bar',
     ]
 
 
 def test_make_database_dump_patterns_treats_empty_names_as_matching_all_databases():
+    flexmock(module).should_receive('make_dump_path').and_return('/dump/path')
     flexmock(module.dump).should_receive('make_database_dump_filename').with_args(
-        module.DUMP_PATH, '*', '*'
+        '/dump/path', '*', '*'
     ).and_return('databases/*/*')
 
-    assert module.make_database_dump_patterns(flexmock(), flexmock(), ()) == ['databases/*/*']
+    assert module.make_database_dump_patterns(flexmock(), flexmock(), {}, ()) == ['databases/*/*']
 
 
 def test_restore_database_dumps_restores_each_database():
     databases = [{'name': 'foo'}, {'name': 'bar'}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     ).and_return('databases/localhost/bar')
@@ -201,11 +211,12 @@ def test_restore_database_dumps_restores_each_database():
             extra_environment=None,
         ).once()
 
-    module.restore_database_dumps(databases, 'test.yaml', dry_run=False)
+    module.restore_database_dumps(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_restore_database_dumps_runs_pg_restore_with_hostname_and_port():
     databases = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     )
@@ -244,11 +255,12 @@ def test_restore_database_dumps_runs_pg_restore_with_hostname_and_port():
         extra_environment=None,
     ).once()
 
-    module.restore_database_dumps(databases, 'test.yaml', dry_run=False)
+    module.restore_database_dumps(databases, 'test.yaml', {}, dry_run=False)
 
 
 def test_restore_database_dumps_runs_pg_restore_with_username_and_password():
     databases = [{'name': 'foo', 'username': 'postgres', 'password': 'trustsome1'}]
+    flexmock(module).should_receive('make_dump_path').and_return('')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
         'databases/localhost/foo'
     )
@@ -283,4 +295,4 @@ def test_restore_database_dumps_runs_pg_restore_with_username_and_password():
         extra_environment={'PGPASSWORD': 'trustsome1'},
     ).once()
 
-    module.restore_database_dumps(databases, 'test.yaml', dry_run=False)
+    module.restore_database_dumps(databases, 'test.yaml', {}, dry_run=False)