Browse Source

Add MySQL database hook "add_drop_database" configuration option to control whether dumped MySQL databases get dropped right before restore (#642).

Dan Helfman 2 years ago
parent
commit
418ebc8843
4 changed files with 37 additions and 1 deletions
  1. 2 0
      NEWS
  2. 7 0
      borgmatic/config/schema.yaml
  3. 1 1
      borgmatic/hooks/mysql.py
  4. 27 0
      tests/unit/hooks/test_mysql.py

+ 2 - 0
NEWS

@@ -1,4 +1,6 @@
 1.7.7
 1.7.7
+ * #642: Add MySQL database hook "add_drop_database" configuration option to control whether dumped
+   MySQL databases get dropped right before restore.
  * #643: Fix for potential data loss (data not getting backed up) when dumping large "directory"
  * #643: Fix for potential data loss (data not getting backed up) when dumping large "directory"
    format PostgreSQL/MongoDB databases. Prior to the fix, these dumps would not finish writing to
    format PostgreSQL/MongoDB databases. Prior to the fix, these dumps would not finish writing to
    disk before Borg consumed them. Now, the dumping process completes before Borg starts. This only
    disk before Borg consumed them. Now, the dumping process completes before Borg starts. This only

+ 7 - 0
borgmatic/config/schema.yaml

@@ -892,6 +892,13 @@ properties:
                                 file of that format, allowing more convenient
                                 file of that format, allowing more convenient
                                 restores of individual databases.
                                 restores of individual databases.
                             example: directory
                             example: directory
+                        add_drop_database:
+                            type: boolean
+                            description: |
+                                Use the "--add-drop-database" flag with
+                                mysqldump, causing the database to be dropped
+                                right before restore. Defaults to true.
+                            example: false
                         options:
                         options:
                             type: string
                             type: string
                             description: |
                             description: |

+ 1 - 1
borgmatic/hooks/mysql.py

@@ -81,7 +81,7 @@ def execute_dump_command(
     dump_command = (
     dump_command = (
         ('mysqldump',)
         ('mysqldump',)
         + (tuple(database['options'].split(' ')) if 'options' in database else ())
         + (tuple(database['options'].split(' ')) if 'options' in database else ())
-        + ('--add-drop-database',)
+        + (('--add-drop-database',) if database.get('add_drop_database', True) else ())
         + (('--host', database['hostname']) if 'hostname' in database else ())
         + (('--host', database['hostname']) if 'hostname' in database else ())
         + (('--port', str(database['port'])) if 'port' in database else ())
         + (('--port', str(database['port'])) if 'port' in database else ())
         + (('--protocol', 'tcp') if 'hostname' in database or 'port' in database else ())
         + (('--protocol', 'tcp') if 'hostname' in database or 'port' in database else ())

+ 27 - 0
tests/unit/hooks/test_mysql.py

@@ -159,6 +159,33 @@ def test_execute_dump_command_runs_mysqldump():
     )
     )
 
 
 
 
+def test_execute_dump_command_runs_mysqldump_without_add_drop_database():
+    process = flexmock()
+    flexmock(module.dump).should_receive('make_database_dump_filename').and_return('dump')
+    flexmock(module.os.path).should_receive('exists').and_return(False)
+    flexmock(module.dump).should_receive('create_named_pipe_for_dump')
+
+    flexmock(module).should_receive('execute_command').with_args(
+        ('mysqldump', '--databases', 'foo', '>', 'dump',),
+        shell=True,
+        extra_environment=None,
+        run_to_completion=False,
+    ).and_return(process).once()
+
+    assert (
+        module.execute_dump_command(
+            database={'name': 'foo', 'add_drop_database': False},
+            log_prefix='log',
+            dump_path=flexmock(),
+            database_names=('foo',),
+            extra_environment=None,
+            dry_run=False,
+            dry_run_label='',
+        )
+        == process
+    )
+
+
 def test_execute_dump_command_runs_mysqldump_with_hostname_and_port():
 def test_execute_dump_command_runs_mysqldump_with_hostname_and_port():
     process = flexmock()
     process = flexmock()
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return('dump')
     flexmock(module.dump).should_receive('make_database_dump_filename').and_return('dump')