diff --git a/CHANGELOG.md b/CHANGELOG.md index 987c603..76dc425 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ Change Log All notable changes to this project are noted in this file. This project adheres to [Semantic Versioning](http://semver.org/). +0.3.1 +----- + +- Fixed the exporter to cope with the non-standard response for months + without usage details. + 0.3.0 ----- diff --git a/azure_costs_exporter/prometheus_collector.py b/azure_costs_exporter/prometheus_collector.py index 74ad621..fae34b2 100644 --- a/azure_costs_exporter/prometheus_collector.py +++ b/azure_costs_exporter/prometheus_collector.py @@ -68,6 +68,10 @@ def _get_azure_data(self, month=None): rsp = requests.get(url, headers=headers, timeout=10) rsp.raise_for_status() + if rsp.text.startswith('"Usage Data Extract"'): + # special treatement for no usage details. Azure API doesn't return a JSON document in that case... + return dict() + return rsp.json() def _create_counter(self): diff --git a/tests/data.py b/tests/data.py index 2925364..113de08 100644 --- a/tests/data.py +++ b/tests/data.py @@ -1,3 +1,7 @@ +api_output_for_empty_months = """"Usage Data Extract", + "", + "AccountOwnerId","Account Name","ServiceAdministratorId","SubscriptionId","SubscriptionGuid","Subscription Name","Date","Month","Day","Year","Product","Meter ID","Meter Category","Meter Sub-Category","Meter Region","Meter Name","Consumed Quantity","ResourceRate","ExtendedCost","Resource Location","Consumed Service","Instance ID","ServiceInfo1","ServiceInfo2","AdditionalInfo","Tags","Store Service Identifier","Department Name","Cost Center","Unit Of Measure","Resource Group",' + """ sample_data = [{u'AccountName': u'Platform', u'AccountOwnerId': u'donald.duck', u'AdditionalInfo': u'', diff --git a/tests/test_app.py b/tests/test_app.py index 674e267..11221ca 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -3,7 +3,7 @@ import datetime from azure_costs_exporter.main import create_app -from .data import sample_data +from .data import sample_data, api_output_for_empty_months @pytest.fixture @@ -61,6 +61,24 @@ def test_metrics(app, now, enrollment): assert rsp.data.count(b'azure_costs_eur') == 4 +@responses.activate +def test_metrics_no_usage(app, now, enrollment): + + + responses.add( + method='GET', + url="https://ea.azure.com/rest/{0}/usage-report?month={1}&type=detail&fmt=Json".format(enrollment, now), + match_querystring=True, + body=api_output_for_empty_months + ) + + rsp = app.test_client().get('/metrics') + assert rsp.status_code == 200 + + # expect only metric definition and help but no content in the output + assert rsp.data.count(b'azure_costs_eur') == 2 + + @responses.activate def test_failing_target(client, now): responses.add( diff --git a/tests/test_collector.py b/tests/test_collector.py index 5abd9c1..0309313 100644 --- a/tests/test_collector.py +++ b/tests/test_collector.py @@ -5,7 +5,7 @@ from azure_costs_exporter.prometheus_collector import convert_json_df, AzureEABillingCollector from azure_costs_exporter.prometheus_collector import base_columns, cost_column -from .data import sample_data +from .data import sample_data, api_output_for_empty_months def current_month(): @@ -59,15 +59,40 @@ def test_extract_metrics(): @responses.activate def test_get_azure_data(): - enrollment='12345' + enrollment = '123' + base_url = "https://ea.azure.com/rest/{}/usage-report".format(enrollment) + params = "?month={}&type=detail&fmt=Json".format(current_month()) + c = AzureEABillingCollector('cloud_costs', enrollment, 'abc123xyz') responses.add( method='GET', - url="https://ea.azure.com/rest/{}/usage-report?month=2017-03&type=detail&fmt=Json".format(enrollment), + url=base_url+params, match_querystring=True, json=sample_data ) - data = c._get_azure_data('2017-03') + data = c._get_azure_data(current_month()) assert data == sample_data + + +@responses.activate +def test_empty_month(): + """ + If no usage details have are available for a given month the API does not return a JSON document. + """ + enrollment = '123' + base_url = "https://ea.azure.com/rest/{}/usage-report".format(enrollment) + params = "?month={}&type=detail&fmt=Json".format(current_month()) + + c = AzureEABillingCollector('cloud_costs', enrollment, 'abc123xyz') + + responses.add( + method='GET', + url=base_url+params, + match_querystring=True, + body=api_output_for_empty_months + ) + + data = c._get_azure_data(current_month()) + assert data == dict()