diff --git a/.gitignore b/.gitignore index 1568c6c..dc1c50b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ file.* -*test* +*test conf/conf.env __pycache__ certs/* diff --git a/logging.json b/logging.json new file mode 100644 index 0000000..5d4bca3 --- /dev/null +++ b/logging.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "formatters": { + "metadata-parser": { + "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + } + }, + "handlers": { + "console": { + "class": "logging.StreamHandler", + "level": "DEBUG", + "formatter": "metadata-parser", + "stream": "ext://sys.stdout" + } + }, + "loggers": { + "MetadataParserClient": { + "level": "DEBUG", + "handlers": [ + "console" + ], + "propagate": "no" + } + }, + "root": { + "level": "DEBUG", + "handlers": [ + "console" + ] + } +} diff --git a/main.py b/main.py index cc70c36..ee80e0c 100644 --- a/main.py +++ b/main.py @@ -1,19 +1,15 @@ -from aiven.client import client from src import explore_service import src.pyvis_display as pyvis_display import configparser +from src.client import MetadataParserClient -# Reading conf.env configuration file with open("conf/conf.env", "r") as f: +# Reading conf.env configuration file config_string = "[DEFAULT]\n" + f.read() config = configparser.ConfigParser() config.read_string(config_string) -# Creating Aiven client instance -myclient = client.AivenClient(base_url=config["DEFAULT"]["BASE_URL"]) - -# Authenticating and storing the token -# result = myclient.authenticate_user(email=config['DEFAULT']['USERNAME'], password=config['DEFAULT']['PASSWORD']) +myclient = MetadataParserClient(config["DEFAULT"]["BASE_URL"], request_timeout=1) myclient.auth_token = config["DEFAULT"]["TOKEN"] # Creating empty nodes and edges lists diff --git a/src/client.py b/src/client.py new file mode 100644 index 0000000..53f43b9 --- /dev/null +++ b/src/client.py @@ -0,0 +1,37 @@ +import json +from logging import getLogger, config as loggingConfig +from requests.exceptions import ConnectionError +from typing import Any +from aiven.client.client import AivenClient, ResponseError + + +class MetadataParserClient(AivenClient): + """MetadataParserClient is a wrapper for aiven-client.""" + + def __init__( + self, base_url: str, show_http: bool = False, request_timeout: int | None = None + ) -> None: + super(MetadataParserClient, self).__init__( + base_url=base_url, show_http=show_http, request_timeout=request_timeout + ) + self.log = getLogger("MetadataParserClient") + with open("logging.json") as json_file: + logConfigDict = json.load(json_file) + loggingConfig.dictConfig(logConfigDict) + + def get_service(self, project: str, service: str) -> dict[str, Any]: + """ + override get_service from AivenClient + handles raised exceptions from get_service and continues excecution + unexpected exceptions are left unhandled + """ + + try: + return super().get_service(project=project, service=service) + except (ConnectionError, ResponseError) as ex: + self.log.warning( + "Error while getting service: %s in project: %s", service, project + ) + self.log.debug("Inner Exception: %s", ex) + + return {} diff --git a/src/explore_service.py b/src/explore_service.py index 4ce7ab6..19be531 100644 --- a/src/explore_service.py +++ b/src/explore_service.py @@ -38,7 +38,7 @@ def populate_service_map(self, service_type, service_name, project): global SERVICE_MAP service = self.get_service(project=project, service=service_name) - if service["state"] != "RUNNING": + if not service or service["state"] != "RUNNING": return try: @@ -99,7 +99,7 @@ def explore(self, service_type, service_name, project): global SERVICE_MAP host = "no-host" service = self.get_service(project=project, service=service_name) - if service["state"] != "RUNNING": + if not service or service["state"] != "RUNNING": return nodes, edges try: diff --git a/tests/test_src_client.py b/tests/test_src_client.py new file mode 100644 index 0000000..3a9ab02 --- /dev/null +++ b/tests/test_src_client.py @@ -0,0 +1,29 @@ +import pytest +from unittest.mock import patch +from requests.exceptions import ConnectionError +from client import MetadataParserClient +from aiven.client.client import AivenClient + +@pytest.fixture +def metadata_parser_client(): + return MetadataParserClient(base_url="https://test.aiven.io", show_http=True, request_timeout=5) + +def test_get_service_unhandled_exception(metadata_parser_client): + # Mock the super().get_service method to raise a RuntimeError + with patch.object(AivenClient, "get_service", side_effect=RuntimeError): + with pytest.raises(RuntimeError): + metadata_parser_client.get_service("test_project", "test_service") + +def test_get_service_handled_exceptions(metadata_parser_client, caplog): + # Mock the super().get_service method to raise a ConnectionError + with patch.object(AivenClient, "get_service", side_effect=ConnectionError): + result = metadata_parser_client.get_service("test_project", "test_service") + assert "Error while getting service: test_service in project: test_project" in caplog.text + assert result == {} + +def test_get_service_no_exception(metadata_parser_client): + expected_service_data = {'service_name': 'test_service', 'project_name': 'test_project'} + # Mock the get_service method to return expected data without raising an exception + with patch.object(metadata_parser_client, 'get_service', return_value=expected_service_data): + result = metadata_parser_client.get_service("test_project", "test_service") + assert result == expected_service_data