Skip to content

Commit

Permalink
Return SUMa API usage info
Browse files Browse the repository at this point in the history
- Add tests
- Add requirements in spec
  • Loading branch information
jesusbv committed Jul 20, 2023
1 parent 8ad9f2a commit 48d8774
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 1 deletion.
1 change: 1 addition & 0 deletions csp-billing-adapter-local.spec
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ BuildRequires: %{python_module pytest-cov}
%endif
Requires: python-setuptools
Requires: python-pluggy
Requires: python-requests
Requires: python-csp-billing-adapter
BuildArch: noarch
%python_subpackages
Expand Down
51 changes: 51 additions & 0 deletions csp_billing_adapter_local/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@

import json
import logging
import requests

from json.decoder import JSONDecodeError
from pathlib import Path

import csp_billing_adapter

from csp_billing_adapter.config import Config
from csp_billing_adapter.exceptions import CSPBillingAdapterException

log = logging.getLogger('CSPBillingAdapter')

Expand Down Expand Up @@ -111,3 +113,52 @@ def save_csp_config(
):
"""Save specified content as local storage csp_config contents."""
update_csp_config(config, csp_config, replace=True)


@csp_billing_adapter.hookimpl(trylast=True)
def get_usage_data(config: Config):
"""
Retrieves the current usage report from API
:param config: The application configuration dictionary
:return: Return a dict with the current usage report
"""
resource = _make_request(config.get('api'))
return _extract_usage(resource, config.get('usage_metrics', {}))


def _extract_usage(resource, usage_metric_names):
"""Parse the response from API to the expected structure."""
usage_metrics = {}
for dimensions in resource.get('dimensions'):
usage_metric_name = dimensions.get('dimension')
if usage_metric_name in usage_metric_names:
usage_metrics[usage_metric_name] = dimensions.get('count')

return usage_metrics


def _make_request(url):
"""Make a request to the API, returns response or raise exception."""
for attempt in range(0, 5):
message = None
try:
response = requests.get(url)
except requests.exceptions.HTTPError as err:
message = f'Http Error: {err}'
except requests.exceptions.ConnectionError as err:
message = f'Error Connecting: {err}'
except requests.exceptions.Timeout as err:
message = f'Timeout Error: {err}'
except requests.exceptions.RequestException as err:
message = f'Request error: {err}'
except Exception as err:
message = f'Unexpected error: {err}'

if not message:
break

if message:
raise CSPBillingAdapterException(f'{message}')

return response.json()
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
csp-billing-adapter @ git+https://github.com/suse-enceladus/csp-billing-adapter@main
pluggy
requests
51 changes: 50 additions & 1 deletion tests/unit/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@
from pathlib import Path
from tempfile import NamedTemporaryFile
from unittest.mock import patch
from pytest import raises

import requests

from csp_billing_adapter.config import Config
from csp_billing_adapter.adapter import get_plugin_manager
from csp_billing_adapter.exceptions import CSPBillingAdapterException


from csp_billing_adapter_local.plugin import (
Expand All @@ -36,7 +40,8 @@
update_cache,
update_csp_config,
save_cache,
save_csp_config
save_csp_config,
get_usage_data
)

config_file = 'tests/data/config.yaml'
Expand Down Expand Up @@ -295,3 +300,47 @@ def test_local_csp_config_save():
)

assert get_csp_config(config=local_config) == test_data2


def test_local_csp_usage_data():
class MockResponse:
def __init__(self, json_data, status_code):
self.json_data = json_data
self.status_code = status_code

def json(self):
return self.json_data

def ok(self):
return self.status_code < 400

json_data = {
"dimensions": [
{"dimension": "managed_node_count", "count": 42}
]
}
status_code = 200
with patch(
'csp_billing_adapter_local.plugin.requests.get',
return_value=MockResponse(json_data, status_code)

):
response = get_usage_data(config=local_config)
assert response == {'managed_node_count': 42}


def test_local_csp_usage_data_errors():
errors = [
requests.exceptions.HTTPError('HTTP'),
requests.exceptions.ConnectionError('Connection'),
requests.exceptions.Timeout('Timeout'),
requests.exceptions.RequestException('Request'),
Exception('Exception')
]
for error in errors:
with patch(
'csp_billing_adapter_local.plugin.requests.get',
side_effect=error
):
with raises(CSPBillingAdapterException):
get_usage_data(config=local_config)

0 comments on commit 48d8774

Please sign in to comment.