From 0d190016d31af50da0ba874c1a2fa3fa9358623f Mon Sep 17 00:00:00 2001 From: Florian Apolloner Date: Thu, 31 Jul 2025 07:58:17 +0200 Subject: [PATCH] rename utils.py to config.py --- .../hooks/data_source/{utils.py => config.py} | 0 borgmatic/hooks/data_source/mariadb.py | 17 ++-- borgmatic/hooks/data_source/mongodb.py | 15 +-- borgmatic/hooks/data_source/mysql.py | 17 ++-- borgmatic/hooks/data_source/postgresql.py | 15 +-- .../hooks/data_source/test_database.py | 10 +- tests/unit/hooks/data_source/test_config.py | 93 +++++++++++++++++++ tests/unit/hooks/data_source/test_utils.py | 93 ------------------- 8 files changed, 133 insertions(+), 127 deletions(-) rename borgmatic/hooks/data_source/{utils.py => config.py} (100%) create mode 100644 tests/unit/hooks/data_source/test_config.py delete mode 100644 tests/unit/hooks/data_source/test_utils.py diff --git a/borgmatic/hooks/data_source/utils.py b/borgmatic/hooks/data_source/config.py similarity index 100% rename from borgmatic/hooks/data_source/utils.py rename to borgmatic/hooks/data_source/config.py diff --git a/borgmatic/hooks/data_source/mariadb.py b/borgmatic/hooks/data_source/mariadb.py index 95949c1d..774a0d4a 100644 --- a/borgmatic/hooks/data_source/mariadb.py +++ b/borgmatic/hooks/data_source/mariadb.py @@ -12,7 +12,8 @@ from borgmatic.execute import ( execute_command_and_capture_output, execute_command_with_processes, ) -from borgmatic.hooks.data_source import dump, utils +from borgmatic.hooks.data_source import config as ds_config +from borgmatic.hooks.data_source import dump logger = logging.getLogger(__name__) @@ -122,7 +123,7 @@ def database_names_to_dump(database, config, username, password, environment, dr ) extra_options, defaults_extra_filename = parse_extra_options(database.get('list_options')) password_transport = database.get('password_transport', 'pipe') - hostname = utils.resolve_database_option('hostname', database) + hostname = ds_config.resolve_database_option('hostname', database) show_command = ( mariadb_show_command + ( @@ -194,7 +195,7 @@ def execute_dump_command( ) extra_options, defaults_extra_filename = parse_extra_options(database.get('options')) password_transport = database.get('password_transport', 'pipe') - hostname = utils.resolve_database_option('hostname', database) + hostname = ds_config.resolve_database_option('hostname', database) dump_command = ( mariadb_dump_command + ( @@ -417,17 +418,17 @@ def restore_data_source_dump( subprocess.Popen) to produce output to consume. ''' dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else '' - hostname = utils.resolve_database_option( + hostname = ds_config.resolve_database_option( 'hostname', data_source, connection_params, restore=True ) - port = utils.resolve_database_option('port', data_source, connection_params, restore=True) - tls = utils.resolve_database_option('tls', data_source, restore=True) + port = ds_config.resolve_database_option('port', data_source, connection_params, restore=True) + tls = ds_config.resolve_database_option('tls', data_source, restore=True) username = borgmatic.hooks.credential.parse.resolve_credential( - utils.resolve_database_option('username', data_source, connection_params, restore=True), + ds_config.resolve_database_option('username', data_source, connection_params, restore=True), config, ) password = borgmatic.hooks.credential.parse.resolve_credential( - utils.resolve_database_option('password', data_source, connection_params, restore=True), + ds_config.resolve_database_option('password', data_source, connection_params, restore=True), config, ) diff --git a/borgmatic/hooks/data_source/mongodb.py b/borgmatic/hooks/data_source/mongodb.py index a2d7d90f..7b91f58d 100644 --- a/borgmatic/hooks/data_source/mongodb.py +++ b/borgmatic/hooks/data_source/mongodb.py @@ -6,7 +6,8 @@ import borgmatic.borg.pattern import borgmatic.config.paths import borgmatic.hooks.credential.parse from borgmatic.execute import execute_command, execute_command_with_processes -from borgmatic.hooks.data_source import dump, utils +from borgmatic.hooks.data_source import config as ds_config +from borgmatic.hooks.data_source import dump logger = logging.getLogger(__name__) @@ -139,7 +140,7 @@ def build_dump_command(database, config, dump_filename, dump_format): dump_command = tuple( shlex.quote(part) for part in shlex.split(database.get('mongodump_command') or 'mongodump') ) - hostname = utils.resolve_database_option('hostname', database) + hostname = ds_config.resolve_database_option('hostname', database) return ( dump_command + (('--out', shlex.quote(dump_filename)) if dump_format == 'directory' else ()) @@ -272,14 +273,16 @@ def build_restore_command(extract_process, database, config, dump_filename, conn ''' Return the custom mongorestore_command from a single database configuration. ''' - hostname = utils.resolve_database_option('hostname', database, connection_params, restore=True) - port = utils.resolve_database_option('port', database, connection_params, restore=True) + hostname = ds_config.resolve_database_option( + 'hostname', database, connection_params, restore=True + ) + port = ds_config.resolve_database_option('port', database, connection_params, restore=True) username = borgmatic.hooks.credential.parse.resolve_credential( - utils.resolve_database_option('username', database, connection_params, restore=True), + ds_config.resolve_database_option('username', database, connection_params, restore=True), config, ) password = borgmatic.hooks.credential.parse.resolve_credential( - utils.resolve_database_option('password', database, connection_params, restore=True), + ds_config.resolve_database_option('password', database, connection_params, restore=True), config, ) diff --git a/borgmatic/hooks/data_source/mysql.py b/borgmatic/hooks/data_source/mysql.py index 9553b0ed..91ad4f8f 100644 --- a/borgmatic/hooks/data_source/mysql.py +++ b/borgmatic/hooks/data_source/mysql.py @@ -12,7 +12,8 @@ from borgmatic.execute import ( execute_command_and_capture_output, execute_command_with_processes, ) -from borgmatic.hooks.data_source import dump, utils +from borgmatic.hooks.data_source import config as ds_config +from borgmatic.hooks.data_source import dump logger = logging.getLogger(__name__) @@ -47,7 +48,7 @@ def database_names_to_dump(database, config, username, password, environment, dr borgmatic.hooks.data_source.mariadb.parse_extra_options(database.get('list_options')) ) password_transport = database.get('password_transport', 'pipe') - hostname = utils.resolve_database_option('hostname', database) + hostname = ds_config.resolve_database_option('hostname', database) show_command = ( mysql_show_command + ( @@ -121,7 +122,7 @@ def execute_dump_command( borgmatic.hooks.data_source.mariadb.parse_extra_options(database.get('options')) ) password_transport = database.get('password_transport', 'pipe') - hostname = utils.resolve_database_option('hostname', database) + hostname = ds_config.resolve_database_option('hostname', database) dump_command = ( mysql_dump_command + ( @@ -348,17 +349,17 @@ def restore_data_source_dump( subprocess.Popen) to produce output to consume. ''' dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else '' - hostname = utils.resolve_database_option( + hostname = ds_config.resolve_database_option( 'hostname', data_source, connection_params, restore=True ) - port = utils.resolve_database_option('port', data_source, connection_params, restore=True) - tls = utils.resolve_database_option('tls', data_source, restore=True) + port = ds_config.resolve_database_option('port', data_source, connection_params, restore=True) + tls = ds_config.resolve_database_option('tls', data_source, restore=True) username = borgmatic.hooks.credential.parse.resolve_credential( - utils.resolve_database_option('username', data_source, connection_params, restore=True), + ds_config.resolve_database_option('username', data_source, connection_params, restore=True), config, ) password = borgmatic.hooks.credential.parse.resolve_credential( - utils.resolve_database_option('password', data_source, connection_params, restore=True), + ds_config.resolve_database_option('password', data_source, connection_params, restore=True), config, ) diff --git a/borgmatic/hooks/data_source/postgresql.py b/borgmatic/hooks/data_source/postgresql.py index 126428b4..3da88345 100644 --- a/borgmatic/hooks/data_source/postgresql.py +++ b/borgmatic/hooks/data_source/postgresql.py @@ -13,7 +13,8 @@ from borgmatic.execute import ( execute_command_and_capture_output, execute_command_with_processes, ) -from borgmatic.hooks.data_source import dump, utils +from borgmatic.hooks.data_source import config as ds_config +from borgmatic.hooks.data_source import dump logger = logging.getLogger(__name__) @@ -32,7 +33,7 @@ def make_environment(database, config, restore_connection_params=None): ''' environment = dict(os.environ) - password = utils.resolve_database_option( + password = ds_config.resolve_database_option( 'password', database, restore_connection_params, restore=restore_connection_params ) @@ -84,7 +85,7 @@ def database_names_to_dump(database, config, environment, dry_run): psql_command = tuple( shlex.quote(part) for part in shlex.split(database.get('psql_command') or 'psql') ) - hostname = utils.resolve_database_option('hostname', database) + hostname = ds_config.resolve_database_option('hostname', database) list_command = ( psql_command + ('--list', '--no-password', '--no-psqlrc', '--csv', '--tuples-only') @@ -189,7 +190,7 @@ def dump_data_sources( ) continue - hostname = utils.resolve_database_option('hostname', database) + hostname = ds_config.resolve_database_option('hostname', database) command = ( dump_command + ( @@ -335,12 +336,12 @@ def restore_data_source_dump( hostname, port, username, and password. ''' dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else '' - hostname = utils.resolve_database_option( + hostname = ds_config.resolve_database_option( 'hostname', data_source, connection_params, restore=True ) - port = utils.resolve_database_option('port', data_source, connection_params, restore=True) + port = ds_config.resolve_database_option('port', data_source, connection_params, restore=True) username = borgmatic.hooks.credential.parse.resolve_credential( - utils.resolve_database_option('username', data_source, connection_params, restore=True), + ds_config.resolve_database_option('username', data_source, connection_params, restore=True), config, ) diff --git a/tests/end-to-end/hooks/data_source/test_database.py b/tests/end-to-end/hooks/data_source/test_database.py index fd9a800f..74030130 100644 --- a/tests/end-to-end/hooks/data_source/test_database.py +++ b/tests/end-to-end/hooks/data_source/test_database.py @@ -9,7 +9,7 @@ import pymongo import pytest import ruamel.yaml -from borgmatic.hooks.data_source import utils +from borgmatic.hooks.data_source import config def write_configuration( @@ -221,10 +221,10 @@ postgresql_databases: def get_connection_params(database, use_restore_options=False): - hostname = utils.resolve_database_option('hostname', database, restore=use_restore_options) - port = utils.resolve_database_option('port', database, restore=use_restore_options) - username = utils.resolve_database_option('username', database, restore=use_restore_options) - password = utils.resolve_database_option('password', database, restore=use_restore_options) + hostname = config.resolve_database_option('hostname', database, restore=use_restore_options) + port = config.resolve_database_option('port', database, restore=use_restore_options) + username = config.resolve_database_option('username', database, restore=use_restore_options) + password = config.resolve_database_option('password', database, restore=use_restore_options) return (hostname, port, username, password) diff --git a/tests/unit/hooks/data_source/test_config.py b/tests/unit/hooks/data_source/test_config.py new file mode 100644 index 00000000..ae3198d0 --- /dev/null +++ b/tests/unit/hooks/data_source/test_config.py @@ -0,0 +1,93 @@ +from subprocess import CalledProcessError + +import pytest +from flexmock import flexmock + +from borgmatic.hooks.data_source import config + + +def test_get_database_option(): + data_source = {'option': 'original_value', 'restore_option': 'restore_value'} + connection_params = {'option': 'connection_value'} + + assert config.resolve_database_option('option', data_source) == 'original_value' + assert config.resolve_database_option('option', data_source, restore=True) == 'restore_value' + assert ( + config.resolve_database_option('option', data_source, connection_params) + == 'connection_value' + ) + assert ( + config.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(config).should_receive('get_ip_from_container').with_args( + 'original_container' + ).and_return('container_ip_1') + flexmock(config).should_receive('get_ip_from_container').with_args( + 'connection_container' + ).and_return('container_ip_2') + flexmock(config).should_receive('get_ip_from_container').with_args( + 'restore_container' + ).and_return('container_ip_3') + + assert config.resolve_database_option('hostname', data_source) == 'container_ip_1' + assert ( + config.resolve_database_option('hostname', data_source, connection_params) + == 'container_ip_2' + ) + assert config.resolve_database_option('hostname', data_source, restore=True) == 'container_ip_3' + + +def test_get_container_ip_without_engines(): + flexmock(config.shutil).should_receive('which').and_return(None).and_return(None) + + with pytest.raises(ValueError): + config.get_ip_from_container('yolo') + + +def test_get_container_ip_success(): + flexmock(config.shutil).should_receive('which').and_return(None).and_return('/usr/bin/podman') + + flexmock(config).should_receive('execute_command_and_capture_output').and_return( + '{"IPAddress": "1.2.3.4"}' + ) + + addr = config.get_ip_from_container('yolo') + assert addr == '1.2.3.4' + + flexmock(config).should_receive('execute_command_and_capture_output').and_return( + '{"Networks": {"my_network": {"IPAddress": "5.6.7.8"}}}' + ) + + assert config.get_ip_from_container('yolo') == '5.6.7.8' + + +def test_get_container_ip_container_not_found(): + flexmock(config.shutil).should_receive('which').and_return('/usr/bin/podman') + flexmock(config).should_receive('execute_command_and_capture_output').and_raise( + CalledProcessError, 1, ['/usr/bin/podman', 'inspect', 'yolo'], None, 'No such object' + ) + + with pytest.raises(CalledProcessError): + config.get_ip_from_container('does not exist') + + +def test_get_container_ip_container_no_network(): + flexmock(config.shutil).should_receive('which').and_return(None).and_return('/usr/bin/podman') + + flexmock(config).should_receive('execute_command_and_capture_output').and_return('{}') + + with pytest.raises(ValueError) as exc_info: + config.get_ip_from_container('yolo') + assert 'Could not determine ip address for container' in str(exc_info.value) diff --git a/tests/unit/hooks/data_source/test_utils.py b/tests/unit/hooks/data_source/test_utils.py deleted file mode 100644 index 0db4c7ec..00000000 --- a/tests/unit/hooks/data_source/test_utils.py +++ /dev/null @@ -1,93 +0,0 @@ -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('{}') - - with pytest.raises(ValueError) as exc_info: - utils.get_ip_from_container('yolo') - assert 'Could not determine ip address for container' in str(exc_info.value)