From 85af3648bebeb6f40a3b7a10f36f3a48d55080b2 Mon Sep 17 00:00:00 2001 From: Israel Barth Rubio Date: Tue, 21 May 2024 10:52:26 -0300 Subject: [PATCH] Fix pg-backup-api so it can handle Barman <= 3.9 pg-backup-api 2.1.0 doesn't work with Barman <= 3.9 because it attempts to fetch models independently of the Barman version it operates on. As Barman models were introduced through version 3.10, pg-backup-api fails with an ugly stack trace: ``` Traceback (most recent call last): File "/usr/lib/python3.9/site-packages/flask/app.py", line 2073, in wsgi_app response = self.full_dispatch_request() File "/usr/lib/python3.9/site-packages/flask/app.py", line 1518, in full_dispatch_request rv = self.handle_user_exception(e) File "/usr/lib/python3.9/site-packages/flask/app.py", line 1516, in full_dispatch_request rv = self.dispatch_request() File "/usr/lib/python3.9/site-packages/flask/app.py", line 1502, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args) File "/usr/lib/python3.9/site-packages/pg_backup_api/logic/utility_controller.py", line 76, in diagnose available_models = barman.__config__.model_names() AttributeError: 'Config' object has no attribute 'model_names' ``` Through this commit we fix pg-backup-api in that sense: * It attempts to use models and the new signature of the `exec_diagnose`, which were introduced by Barman 3.10; * It falls back to the old signature of `exec_diagnose` if models are not available (Barman <= 3.9). References: BAR-171. Signed-off-by: Israel Barth Rubio --- .../pg_backup_api/logic/utility_controller.py | 24 ++++++++++++------- .../tests/test_utility_controller.py | 23 ++++++++++++++++++ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/pg_backup_api/pg_backup_api/logic/utility_controller.py b/pg_backup_api/pg_backup_api/logic/utility_controller.py index 2fd4688..5b9d97d 100644 --- a/pg_backup_api/pg_backup_api/logic/utility_controller.py +++ b/pg_backup_api/pg_backup_api/logic/utility_controller.py @@ -73,18 +73,24 @@ def diagnose() -> 'Response': else: server_dict[server] = Server(conf) - available_models = barman.__config__.model_names() - model_dict = {} - for model in available_models: # pyright: ignore - model_dict[model] = barman.__config__.get_model(model) - # errors list with duplicate paths between servers errors_list = barman.__config__.servers_msg_list - barman_diagnose.exec_diagnose(server_dict, - model_dict, - errors_list, - show_config_source=False) + try: + available_models = barman.__config__.model_names() + model_dict = {} + for model in available_models: # pyright: ignore + model_dict[model] = barman.__config__.get_model(model) + + barman_diagnose.exec_diagnose(server_dict, + model_dict, + errors_list, + show_config_source=False) + # An attribute error is thown when calling `model_names()` if using Barman + # older than 3.10, in which case models are not yet implemented, so we fall + # back to the old signature of diagnose command. + except AttributeError: + barman_diagnose.exec_diagnose(server_dict, errors_list) # new outputs are appended, so grab the last one stored_output = json.loads(output._writer.json_output["_INFO"][-1]) diff --git a/pg_backup_api/pg_backup_api/tests/test_utility_controller.py b/pg_backup_api/pg_backup_api/tests/test_utility_controller.py index b7cc281..b8600c9 100644 --- a/pg_backup_api/pg_backup_api/tests/test_utility_controller.py +++ b/pg_backup_api/pg_backup_api/tests/test_utility_controller.py @@ -91,6 +91,29 @@ def test_diagnose_ok(self, client): assert response.status_code == 200 assert response.data == b'{"global":{"config":{}}}\n' + @patch("pg_backup_api.logic.utility_controller.barman_diagnose", Mock()) + @patch.dict( + "pg_backup_api.logic.utility_controller.output._writer.json_output", + { + '_INFO': ['SOME', 'JSON', 'ENTRIES', '{"global":{"config":{}}}'], + }, + ) + def test_diagnose_ok_old_barman(self, client): + """Test ``/diagnose`` endpoint. + + Ensure a ``GET`` request returns ``200`` and the expected JSON output, + even if using Barman 3.9 or older, in which case models implementation + is not available. + """ + path = "/diagnose" + + with patch("barman.__config__") as mock_config: + mock_config.model_names.side_effect = AttributeError("Old Barman") + response = client.get(path) + + assert response.status_code == 200 + assert response.data == b'{"global":{"config":{}}}\n' + def test_diagnose_not_allowed(self, client): """Test ``/diagnose`` endpoint.