Florian Apolloner 1 месяц назад
Родитель
Сommit
04cc58a5c7

+ 14 - 2
borgmatic/actions/restore.py

@@ -176,7 +176,13 @@ def restore_single_dump(
     that data source from the archive.
     '''
     dump_metadata = render_dump_metadata(
-        Dump(hook_name, data_source['name'], data_source.get('hostname'), data_source.get('port'), data_source.get('label')),
+        Dump(
+            hook_name,
+            data_source['name'],
+            data_source.get('hostname'),
+            data_source.get('port'),
+            data_source.get('label'),
+        ),
     )
 
     logger.info(f'Restoring data source {dump_metadata}')
@@ -568,7 +574,13 @@ def run_restore(
             if not found_data_source:
                 found_data_source = get_configured_data_source(
                     config,
-                    Dump(restore_dump.hook_name, 'all', restore_dump.hostname, restore_dump.port, restore_dump.label),
+                    Dump(
+                        restore_dump.hook_name,
+                        'all',
+                        restore_dump.hostname,
+                        restore_dump.port,
+                        restore_dump.label,
+                    ),
                 )
 
                 if not found_data_source:

+ 2 - 1
borgmatic/hooks/data_source/utils.py

@@ -9,6 +9,7 @@ IS_A_HOOK = False
 
 logger = logging.getLogger(__name__)
 
+
 def resolve_database_option(option, data_source, connection_params=None, restore=False):
     # Special case `hostname` since it overlaps with `container`
     if option == 'hostname':
@@ -24,7 +25,7 @@ def _get_hostname_from_config(data_source, connection_params=None, restore=False
     # connection params win, full stop
     if connection_params:
         if container := connection_params.get('container'):
-            return container
+            return get_ip_from_container(container)
         if hostname := connection_params.get('hostname'):
             return hostname
     # ... then try the restore config

+ 1 - 1
tests/unit/actions/test_restore.py

@@ -1102,7 +1102,7 @@ def test_run_restore_restores_each_data_source():
             username=None,
             password=None,
             restore_path=None,
-            container=None
+            container=None,
         ),
         global_arguments=flexmock(dry_run=False),
         local_path=flexmock(),

+ 91 - 0
tests/unit/hooks/data_source/test_utils.py

@@ -0,0 +1,91 @@
+from subprocess import CalledProcessError
+
+import pytest
+from flexmock import flexmock
+
+from borgmatic.hooks.data_source import utils
+
+
+def test_get_database_option():
+    data_source = {'option': 'original_value', 'restore_option': 'restore_value'}
+    connection_params = {'option': 'connection_value'}
+
+    assert utils.resolve_database_option('option', data_source) == 'original_value'
+    assert utils.resolve_database_option('option', data_source, restore=True) == 'restore_value'
+    assert (
+        utils.resolve_database_option('option', data_source, connection_params)
+        == 'connection_value'
+    )
+    assert (
+        utils.resolve_database_option('option', data_source, connection_params, restore=True)
+        == 'connection_value'
+    )
+
+
+def test_get_hostname_option_via_container():
+    data_source = {
+        'container': 'original_container',
+        'hostname': 'original_hostname',
+        'restore_container': 'restore_container',
+        'restore_hostname': 'restore_hostname',
+    }
+    connection_params = {'container': 'connection_container', 'hostname': 'connection_hostname'}
+
+    flexmock(utils).should_receive('get_ip_from_container').with_args(
+        'original_container'
+    ).and_return('container_ip_1')
+    flexmock(utils).should_receive('get_ip_from_container').with_args(
+        'connection_container'
+    ).and_return('container_ip_2')
+    flexmock(utils).should_receive('get_ip_from_container').with_args(
+        'restore_container'
+    ).and_return('container_ip_3')
+
+    assert utils.resolve_database_option('hostname', data_source) == 'container_ip_1'
+    assert (
+        utils.resolve_database_option('hostname', data_source, connection_params)
+        == 'container_ip_2'
+    )
+    assert utils.resolve_database_option('hostname', data_source, restore=True) == 'container_ip_3'
+
+
+def test_get_container_ip_without_engines():
+    flexmock(utils.shutil).should_receive('which').and_return(None).and_return(None)
+
+    with pytest.raises(ValueError):
+        utils.get_ip_from_container('yolo')
+
+
+def test_get_container_ip_success():
+    flexmock(utils.shutil).should_receive('which').and_return(None).and_return('/usr/bin/podman')
+
+    flexmock(utils).should_receive('execute_command_and_capture_output').and_return(
+        '{"IPAddress": "1.2.3.4"}'
+    )
+
+    addr = utils.get_ip_from_container('yolo')
+    assert addr == '1.2.3.4'
+
+    flexmock(utils).should_receive('execute_command_and_capture_output').and_return(
+        '{"Networks": {"my_network": {"IPAddress": "5.6.7.8"}}}'
+    )
+
+    assert utils.get_ip_from_container('yolo') == '5.6.7.8'
+
+
+def test_get_container_ip_container_not_found():
+    flexmock(utils.shutil).should_receive('which').and_return('/usr/bin/podman')
+    flexmock(utils).should_receive('execute_command_and_capture_output').and_raise(
+        CalledProcessError, 1, ['/usr/bin/podman', 'inspect', 'yolo'], None, 'No such object'
+    )
+
+    with pytest.raises(CalledProcessError):
+        utils.get_ip_from_container('does not exist')
+
+
+def test_get_container_ip_container_no_network():
+    flexmock(utils.shutil).should_receive('which').and_return(None).and_return('/usr/bin/podman')
+
+    flexmock(utils).should_receive('execute_command_and_capture_output').and_return('{}')
+
+    assert utils.get_ip_from_container('yolo') is None