def test_get_resolution_empty_default(self): """Test get_resolution returns default when query params are empty.""" query_params = {} handler = ReportQueryHandler(query_params, '', self.tenant, 'unblended_cost', 'currency_code') self.assertEqual(handler.get_resolution(), 'daily') self.assertEqual(handler.get_resolution(), 'daily')
def test_get_time_scope_value_empty_default(self): """Test get_time_scope_value returns default when query params are empty.""" query_params = {} handler = ReportQueryHandler(query_params, '', self.tenant, 'unblended_cost', 'currency_code') self.assertEqual(handler.get_time_scope_value(), -10) self.assertEqual(handler.get_time_scope_value(), -10)
def test_get_group_by_with_service_list(self): """Test the get_group_by_data method with no data in the query params.""" expected = ['a', 'b'] query_string = '?group_by[service]=a&group_by[service]=b' handler = ReportQueryHandler({'group_by': { 'service': expected }}, query_string, self.tenant, 'unblended_cost', 'currency_code') service = handler.get_group_by_data('service') self.assertEqual(expected, service)
def test_has_filter_with_filter(self): """Test the has_filter method with filter in the query params.""" query_params = { 'filter': { 'resolution': 'monthly', 'time_scope_value': -1 } } handler = ReportQueryHandler(query_params, '', self.tenant, 'unblended_cost', 'currency_code') self.assertIsNotNone( handler.check_query_params('filter', 'time_scope_value'))
def test_execute_query_current_month_monthly(self): """Test execute_query for current month on monthly breakdown.""" query_params = { 'filter': { 'resolution': 'monthly', 'time_scope_value': -1, 'time_scope_units': 'month' } } handler = ReportQueryHandler(query_params, '', self.tenant, 'unblended_cost', 'currency_code') query_output = handler.execute_query() self.assertIsNotNone(query_output.get('data')) self.assertIsNotNone(query_output.get('total')) total = query_output.get('total') self.assertIsNotNone(total.get('value')) self.assertEqual(total.get('value'), Decimal('4.776000000'))
def _generic_report(request, aggregate_key, units_key, **kwargs): """Generically query for reports. Args: request (Request): The HTTP request object aggregate_key (str): The report metric to be aggregated e.g. 'usage_amount' or 'unblended_cost' units_key (str): The field used to establish the reporting unit Returns: (Response): The report in a Response object """ LOG.info(f'API: {request.path} USER: {request.user.username}') url_data = request.GET.urlencode() validation, params = process_query_parameters(url_data) if not validation: return Response(data=params, status=status.HTTP_400_BAD_REQUEST) tenant = get_tenant(request.user) if kwargs: kwargs['accept_type'] = request.META.get('HTTP_ACCEPT') else: kwargs = {'accept_type': request.META.get('HTTP_ACCEPT')} handler = ReportQueryHandler(params, url_data, tenant, aggregate_key, units_key, **kwargs) output = handler.execute_query() if 'units' in params: from_unit = _find_unit()(output['data']) if from_unit: try: to_unit = params['units'] unit_converter = UnitConverter() output = _fill_in_missing_units(from_unit)(output) output = _convert_units(unit_converter, output, to_unit) except (DimensionalityError, UndefinedUnitError): error = {'details': _('Unit conversion failed.')} raise ValidationError(error) LOG.debug(f'DATA: {output}') return Response(output)
def test_get_time_frame_filter_last_thirty(self): """Test _get_time_frame_filter for last thirty days.""" query_params = { 'filter': { 'resolution': 'daily', 'time_scope_value': -30, 'time_scope_units': 'day' } } handler = ReportQueryHandler(query_params, '', self.tenant, 'unblended_cost', 'currency_code') current_day = timezone.now().replace(microsecond=0, second=0, minute=0) ten_days_ago = ReportQueryHandler.n_days_ago(current_day, 30) start = handler.start_datetime end = handler.end_datetime interval = handler.time_interval self.assertEqual(start, ten_days_ago) self.assertEqual(end, current_day) self.assertIsInstance(interval, list) self.assertTrue(len(interval) == 31)
def test_execute_query_by_account_by_service(self): """Test execute_query for current month breakdown by account by service.""" query_params = { 'filter': { 'resolution': 'monthly', 'time_scope_value': -1, 'time_scope_units': 'month' }, 'group_by': { 'account': ['*'], 'service': ['*'] } } query_string = '?group_by[account]=*&group_by[service]=Compute Instance' handler = ReportQueryHandler(query_params, query_string, self.tenant, 'unblended_cost', 'currency_code') query_output = handler.execute_query() data = query_output.get('data') self.assertIsNotNone(data) self.assertIsNotNone(query_output.get('total')) total = query_output.get('total') self.assertIsNotNone(total.get('value')) self.assertEqual(total.get('value'), Decimal('4.776000000')) current_month = timezone.now().replace(microsecond=0, second=0, minute=0, hour=0, day=1) cmonth_str = current_month.strftime('%Y-%m') for data_item in data: month_val = data_item.get('date') month_data = data_item.get('accounts') self.assertEqual(month_val, cmonth_str) self.assertIsInstance(month_data, list) for month_item in month_data: account = month_item.get('account') self.assertEqual(account, self.payer_account_id) self.assertIsInstance(month_item.get('services'), list)
def test_get_time_frame_filter_previous_month(self): """Test _get_time_frame_filter for previous month.""" query_params = { 'filter': { 'resolution': 'daily', 'time_scope_value': -2, 'time_scope_units': 'month' } } handler = ReportQueryHandler(query_params, '', self.tenant, 'unblended_cost', 'currency_code') current_month = timezone.now().replace(microsecond=0, second=0, minute=0, hour=0, day=1) prev_month = ReportQueryHandler.previous_month(current_month) start = handler.start_datetime end = handler.end_datetime interval = handler.time_interval self.assertEqual(start, prev_month) self.assertEqual(end, current_month) self.assertIsInstance(interval, list) self.assertTrue(len(interval) >= 28)
def test_get_time_scope_value_empty_day_time_scope(self): """Test get_time_scope_value returns default when time_scope is month.""" query_params = {'filter': {'time_scope_units': 'day'}} handler = ReportQueryHandler(query_params, '', self.tenant, 'unblended_cost', 'currency_code') self.assertEqual(handler.get_time_scope_value(), -10)
def test_get_resolution_empty_day_time_scope(self): """Test get_resolution returns default when time_scope is month.""" query_params = {'filter': {'time_scope_value': -10}} handler = ReportQueryHandler(query_params, '', self.tenant, 'unblended_cost', 'currency_code') self.assertEqual(handler.get_resolution(), 'daily')
def test_get_group_by_no_data(self): """Test the get_group_by_data method with no data in the query params.""" handler = ReportQueryHandler({}, '', self.tenant, 'unblended_cost', 'currency_code') self.assertFalse(handler.get_group_by_data('service'))
def test_has_filter_no_filter(self): """Test the has_filter method with no filter in the query params.""" handler = ReportQueryHandler({}, '', self.tenant, 'unblended_cost', 'currency_code') self.assertFalse( handler.check_query_params('filter', 'time_scope_value'))
def costs(request): """Get cost data. @api {get} /api/v1/reports/costs/ Get cost data @apiName getCostData @apiGroup Report @apiVersion 1.0.0 @apiDescription Get cost data. @apiHeader {String} token User authorization token. @apiHeaderExample {json} Header-Example: { "Authorization": "Token 45138a913da44ab89532bab0352ef84b" } @apiParam (Query Param) {Object} filter The filter to apply to the report. @apiParam (Query Param) {Object} group_by The grouping to apply to the report. @apiParam (Query Param) {Object} order_by The ordering to apply to the report. @apiParamExample {json} Query Param: ?filter[resolution]=daily&filter[time_scope_value]=-10&order_by[cost]=asc @apiSuccess {Object} group_by The grouping to applied to the report. @apiSuccess {Object} order_by The ordering to applied to the report @apiSuccess {Object} filter The filter to applied to the report. @apiSuccess {Object} data The report data. @apiSuccessExample {json} Success-Response: HTTP/1.1 200 OK { "group_by": { "account": [ "*" ] }, "order_by": { "cost": "asc" }, "filter": { "resolution": "daily", "time_scope_value": -10, "time_scope_units": "day", "resource_scope": [] }, "data": [ [ { "date": "2018-05-28", "accounts": [ { "account": "8577742690384", "values": [ { "date": "2018-05-28", "units": "USD", "account": "8577742690384", "total": 1498.92962634 } ] }, { "account": "9420673783214", "values": [ { "date": "2018-05-28", "units": "USD", "account": "9420673783214", "total": 1065.845524241 } ] } ] } ] ] } """ url_data = request.GET.urlencode() validation, value = process_query_parameters(url_data) if not validation: return Response(data=value, status=status.HTTP_400_BAD_REQUEST) tenant = get_tenant(request.user) handler = ReportQueryHandler(value, url_data, tenant, 'unblended_cost', 'currency_code') output = handler.execute_query() return Response(output)
def storage(request): """Get inventory storage data. @api {get} /api/v1/reports/inventory/storage Get inventory storage data @apiName getInventoryStorageData @apiGroup Report @apiVersion 1.0.0 @apiDescription Get inventory data. @apiHeader {String} token User authorization token. @apiHeaderExample {json} Header-Example: { "Authorization": "Token 45138a913da44ab89532bab0352ef84b" } @apiParam (Query Param) {Object} filter The filter to apply to the report. @apiParam (Query Param) {Object} group_by The grouping to apply to the report. @apiParam (Query Param) {Object} order_by The ordering to apply to the report. @apiParamExample {json} Query Param: ?filter[resolution]=daily&filter[time_scope_value]=-10&order_by[cost]=asc @apiSuccess {Object} group_by The grouping to applied to the report. @apiSuccess {Object} filter The filter to applied to the report. @apiSuccess {Object} data The report data. @apiSuccessExample {json} Success-Response: HTTP/1.1 200 OK { "group_by": { "account": [ "*" ] }, "filter": { "resolution": "monthly", "time_scope_value": -1, "time_scope_units": "month", "resource_scope": [] }, "data": [ [ { "date": "2018-07", "accounts": [ { "account": "4418636104713", "values": [ { "date": "2018-07", "units": "GB-Mo", "account": "4418636104713", "total": 1826.74238146924 } ] }, { "account": "8577742690384", "values": [ { "date": "2018-07", "units": "GB-Mo", "account": "8577742690384", "total": 1137.74036198065 } ] }, { "account": "3474227945050", "values": [ { "date": "2018-07", "units": "GB-Mo", "account": "3474227945050", "total": 1045.80659412797 } ] }, { "account": "7249815104968", "values": [ { "date": "2018-07", "units": "GB-Mo", "account": "7249815104968", "total": 807.326470618818 } ] }, { "account": "9420673783214", "values": [ { "date": "2018-07", "units": "GB-Mo", "account": "9420673783214", "total": 658.306642830709 } ] } ] } ] ] } """ url_data = request.GET.urlencode() validation, value = process_query_parameters(url_data) if not validation: return Response(data=value, status=status.HTTP_400_BAD_REQUEST) tenant = get_tenant(request.user) filter_scope = {'cost_entry_product__product_family': 'Storage'} extras = {'filter': filter_scope} handler = ReportQueryHandler(value, url_data, tenant, 'usage_amount', 'cost_entry_pricing__unit', **extras) output = handler.execute_query() return Response(output)
def instance_type(request): """Get inventory data. @api {get} /api/v1/reports/inventory/instance-type/ Get inventory instance type data @apiName getInventoryInstanceTypeData @apiGroup Report @apiVersion 1.0.0 @apiDescription Get inventory instance type data. @apiHeader {String} token User authorization token. @apiHeaderExample {json} Header-Example: { "Authorization": "Token 45138a913da44ab89532bab0352ef84b" } @apiParam (Query Param) {Object} filter The filter to apply to the report. @apiParam (Query Param) {Object} group_by The grouping to apply to the report. @apiParam (Query Param) {Object} order_by The ordering to apply to the report. @apiParamExample {json} Query Param: ?filter[resolution]=daily&filter[time_scope_value]=-10&order_by[cost]=asc @apiSuccess {Object} group_by The grouping to applied to the report. @apiSuccess {Object} filter The filter to applied to the report. @apiSuccess {Object} data The report data. @apiSuccessExample {json} Success-Response: HTTP/1.1 200 OK { "group_by": { "account": [ "*" ] }, "filter": { "resolution": "daily", "time_scope_value": -10, "time_scope_units": "day", "resource_scope": [] }, "data": [ [ { "date": "2018-05-28", "instance_types": [ { "instance_type": "t2.medium", "values": [ { "date": "2018-05-28", "units": "Hrs", "instance_type": "t2.medium", "total": 5 } ] }, { "instance_type": "m5.2xlarge", "values": [ { "date": "2018-05-28", "units": "Hrs", "instance_type": "m5.2xlarge", "total": 29 } ] } ] } ] ] } """ url_data = request.GET.urlencode() validation, value = process_query_parameters(url_data) if not validation: return Response(data=value, status=status.HTTP_400_BAD_REQUEST) tenant = get_tenant(request.user) filter_scope = {'cost_entry_product__instance_type__isnull': False} annotations = { 'instance_type': Concat('cost_entry_product__instance_type', Value('')) } extras = { 'filter': filter_scope, 'annotations': annotations, 'group_by': ['instance_type'] } handler = ReportQueryHandler(value, url_data, tenant, 'usage_amount', 'cost_entry_pricing__unit', **extras) output = handler.execute_query() return Response(output)