def _generic_report(request, provider, report): """Generically query for reports. Args: request (Request): The HTTP request object provider (String): Provider name (e.g. 'aws' or 'ocp') report (String): Report name (e.g. 'cost', 'cpu', 'memory'); used to access ReportMap Returns: (Response): The report in a Response object """ LOG.debug(f'API: {request.path} USER: {request.user.username}') tenant = get_tenant(request.user) cm = ClassMapper() provider_query_hdlr = cm.query_handler(provider, report) provider_parameter_serializer = cm.serializer(provider, report) tag_keys = [] if report != 'tags': tag_models = cm.tag_handler(provider, report) for tag_model in tag_models: tag_keys.extend(get_tag_keys(request, tag_model)) url_data = request.GET.urlencode() validation, params = process_query_parameters( url_data, provider_parameter_serializer, tag_keys, request=request) if not validation: return Response(data=params, status=status.HTTP_400_BAD_REQUEST) handler = provider_query_hdlr(params, url_data, tenant, accept_type=request.META.get('HTTP_ACCEPT'), report_type=report, tag_keys=tag_keys, access=request.user.access) output = handler.execute_query() max_rank = handler.max_rank 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) paginator = get_paginator(params.get('filter', {}), max_rank) paginated_result = paginator.paginate_queryset(output, request) LOG.debug(f'DATA: {output}') return paginator.get_paginated_response(paginated_result)
def get(self, request): """Get Report Data. This method is responsible for passing request data to the reporting APIs. Args: request (Request): The HTTP request object Returns: (Response): The report in a Response object """ LOG.debug(f'API: {request.path} USER: {request.user.username}') tenant = get_tenant(request.user) tag_keys = [] if self.report != 'tags': for tag_model in self._tag_handler: tag_keys.extend(get_tag_keys(request, tag_model)) url_data = request.GET.urlencode() validation, params = process_query_parameters(url_data, self._serializer, tag_keys, request=request) if not validation: return Response(data=params, status=status.HTTP_400_BAD_REQUEST) handler = self._query_handler( params, url_data, tenant, accept_type=request.META.get('HTTP_ACCEPT'), report_type=self.report, tag_keys=tag_keys, access=request.user.access) output = handler.execute_query() max_rank = handler.max_rank 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) paginator = get_paginator(params.get('filter', {}), max_rank) paginated_result = paginator.paginate_queryset(output, request) LOG.debug(f'DATA: {output}') return paginator.get_paginated_response(paginated_result)
def test_convert_units_success(self): """Test unit conversion succeeds.""" converter = UnitConverter() to_unit = "byte" expected_unit = f"{to_unit}-Mo" report_total = self.report.get("total", {}).get("value") result = _convert_units(converter, self.report, to_unit) result_unit = result.get("total", {}).get("units") result_total = result.get("total", {}).get("value") self.assertEqual(expected_unit, result_unit) self.assertEqual(report_total * 1e9, result_total)
def test_convert_units_success(self): """Test unit conversion succeeds.""" converter = UnitConverter() to_unit = 'byte' expected_unit = f'{to_unit}-Mo' report_total = self.report.get('total', {}).get('value') result = _convert_units(converter, self.report, to_unit) result_unit = result.get('total', {}).get('units') result_total = result.get('total', {}).get('value') self.assertEqual(expected_unit, result_unit) self.assertEqual(report_total * 1E9, result_total)
def test_convert_units_total_not_dict(self): """Test that the total not dict block is hit.""" converter = UnitConverter() to_unit = "byte" expected_unit = f"{to_unit}-Mo" report = self.report["data"][0]["accounts"][0]["values"][0] report_total = report.get("total") result = _convert_units(converter, report, to_unit) result_unit = result.get("units") result_total = result.get("total") self.assertEqual(expected_unit, result_unit) self.assertEqual(report_total * 1e9, result_total)
def test_convert_units_list(self): """Test that the list check is hit.""" converter = UnitConverter() to_unit = "byte" expected_unit = f"{to_unit}-Mo" report_total = self.report.get("total", {}).get("value") report = [self.report] result = _convert_units(converter, report, to_unit) result_unit = result[0].get("total", {}).get("units") result_total = result[0].get("total", {}).get("value") self.assertEqual(expected_unit, result_unit) self.assertEqual(report_total * 1e9, result_total)
def test_convert_units_total_not_dict(self): """Test that the total not dict block is hit.""" converter = UnitConverter() to_unit = 'byte' expected_unit = f'{to_unit}-Mo' report = self.report['data'][0]['accounts'][0]['values'][0] report_total = report.get('total') result = _convert_units(converter, report, to_unit) result_unit = result.get('units') result_total = result.get('total') self.assertEqual(expected_unit, result_unit) self.assertEqual(report_total * 1E9, result_total)
def test_convert_units_list(self): """Test that the list check is hit.""" converter = UnitConverter() to_unit = 'byte' expected_unit = f'{to_unit}-Mo' report_total = self.report.get('total', {}).get('value') report = [self.report] result = _convert_units(converter, report, to_unit) result_unit = result[0].get('total', {}).get('units') result_total = result[0].get('total', {}).get('value') self.assertEqual(expected_unit, result_unit) self.assertEqual(report_total * 1E9, result_total)
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 validate_units(self, value): """Validate incoming units data. Args: data (Dict): data to be validated Returns: (Dict): Validated data Raises: (ValidationError): if units field inputs are invalid """ unit_converter = UnitConverter() try: unit_converter.validate_unit(value) except (AttributeError, UndefinedUnitError): error = {'units': f'{value} is not a supported unit'} raise serializers.ValidationError(error) return value
def _generic_report(request, provider_parameter_serializer, provider_query_hdlr, **kwargs): """Generically query for reports. Args: request (Request): The HTTP request object Returns: (Response): The report in a Response object """ LOG.info(f'API: {request.path} USER: {request.user.username}') tenant = get_tenant(request.user) if kwargs: kwargs['accept_type'] = request.META.get('HTTP_ACCEPT') else: kwargs = {'accept_type': request.META.get('HTTP_ACCEPT')} tag_keys = kwargs.get('tag_keys', []) url_data = request.GET.urlencode() validation, params = process_query_parameters( url_data, provider_parameter_serializer, tag_keys) if not validation: return Response(data=params, status=status.HTTP_400_BAD_REQUEST) handler = provider_query_hdlr(params, url_data, tenant, **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 get(self, request): """Get Report Data. This method is responsible for passing request data to the reporting APIs. Args: request (Request): The HTTP request object Returns: (Response): The report in a Response object """ LOG.debug(f'API: {request.path} USER: {request.user.username}') try: params = QueryParameters(request=request, caller=self) except ValidationError as exc: return Response(data=exc.detail, status=status.HTTP_400_BAD_REQUEST) handler = self.query_handler(params) output = handler.execute_query() max_rank = handler.max_rank if 'units' in params.parameters: from_unit = _find_unit()(output['data']) if from_unit: try: to_unit = params.parameters.get('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) paginator = get_paginator(params.parameters.get('filter', {}), max_rank) paginated_result = paginator.paginate_queryset(output, request) LOG.debug(f'DATA: {output}') return paginator.get_paginated_response(paginated_result)
def setUpClass(cls): """Set up for test class.""" super().setUpClass() cls.converter = UnitConverter()