Rename get_usage to get_measurements

The costs.py was removed erroneously in previous patch, but it broke
/measurements API.

This patch adds it back but with a different file name to keep
consistency with other APIs.

Add unit tests as well.

Change-Id: Ib34b01d4dca4fb8faf559ba08ba18de7372ecf04
This commit is contained in:
Lingxian Kong 2017-05-26 13:57:28 +12:00
parent 2ff5b1518c
commit 0ab71bae06
8 changed files with 204 additions and 5 deletions

View File

@ -22,9 +22,9 @@ from distil.api import acl
from distil.common import api
from distil.common import constants
from distil.common import openstack
from distil.service.api.v2 import costs
from distil.service.api.v2 import health
from distil.service.api.v2 import invoices
from distil.service.api.v2 import measurements
from distil.service.api.v2 import products
from distil.service.api.v2 import quotations
@ -91,7 +91,7 @@ def measurements_get():
params = _get_request_args()
return api.render(
measurements=costs.get_usage(
measurements=measurements.get_measurements(
params['project_id'], params['start'], params['end']
)
)

View File

@ -16,15 +16,15 @@
from oslo_config import cfg
from oslo_log import log as logging
from distil.common import general
from distil.erp import utils as erp_utils
from distil.service.api.v2 import utils
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
def get_invoices(project_id, start, end, detailed=False):
project, start, end = utils.convert_project_and_range(
project, start, end = general.convert_project_and_range(
project_id, start, end)
LOG.info(

View File

@ -0,0 +1,63 @@
# Copyright (c) 2016 Catalyst IT Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
from oslo_log import log as logging
from distil.common import general
from distil.db import api as db_api
LOG = logging.getLogger(__name__)
def _build_project_dict(project, usage):
"""Builds a dict structure for a given project."""
project_dict = {'project_name': project.name, 'project_id': project.id}
all_resource_ids = [entry.get('resource_id') for entry in usage]
res_list = db_api.resource_get_by_ids(project.id, all_resource_ids)
project_dict['resources'] = {row.id: json.loads(row.info)
for row in res_list}
for entry in usage:
service = {'name': entry.get('service'),
'volume': entry.get('volume'),
'unit': entry.get('unit')}
resource = project_dict['resources'][entry.get('resource_id')]
service_list = resource.setdefault('services', [])
service_list.append(service)
return project_dict
def get_measurements(project_id, start, end):
valid_project, start, end = general.convert_project_and_range(
project_id, start, end)
LOG.debug("Get measurements for %s in range: %s - %s" %
(valid_project.id, start, end))
usage = db_api.usage_get(valid_project.id, start, end)
project_dict = _build_project_dict(valid_project, usage)
# add range:
project_dict['start'] = str(start)
project_dict['end'] = str(end)
return project_dict

View File

@ -0,0 +1,45 @@
# Copyright (C) 2017 Catalyst IT Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from datetime import datetime
import mock
from distil.service.api.v2 import invoices
from distil.tests.unit import base
class InvoicesTest(base.DistilWithDbTestCase):
@mock.patch('distil.common.general.convert_project_and_range')
@mock.patch('stevedore.driver.DriverManager')
def test_get_invoices(self, mock_driver, mock_convert):
class Project(object):
def __init__(self, id, name):
self.id = id
self.name = name
start = datetime.utcnow()
end = datetime.utcnow()
mock_convert.return_value = (
Project('123', 'fake_project'), start, end
)
driver_manager = mock_driver.return_value
driver = driver_manager.driver
invoices.get_invoices('123', str(start), str(end))
driver.get_invoices.assert_called_once_with(
start, end, '123', detailed=False
)

View File

@ -0,0 +1,91 @@
# Copyright (C) 2017 Catalyst IT Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from datetime import datetime
import json
import mock
from distil.service.api.v2 import measurements
from distil.tests.unit import base
class MeasurementsTest(base.DistilWithDbTestCase):
@mock.patch('distil.common.general.convert_project_and_range')
@mock.patch('distil.db.api.usage_get')
@mock.patch('distil.db.api.resource_get_by_ids')
def test_get_measurements(self, mock_get_resources, mock_db_usage_get,
mock_convert):
class Project(object):
def __init__(self, id, name):
self.id = id
self.name = name
start = datetime.utcnow()
end = datetime.utcnow()
mock_convert.return_value = (
Project('123', 'fake_name'), start, end
)
mock_db_usage_get.return_value = [
{
'resource_id': '111',
'service': 'srv1',
'volume': 10,
'unit': 'byte',
},
{
'resource_id': '222',
'service': 'srv2',
'volume': 20,
'unit': 'byte',
}
]
class Resource(object):
def __init__(self, id, info):
self.id = id
self.info = info
res1 = Resource('111', json.dumps({'name': 'resource1'}))
res2 = Resource('222', json.dumps({'name': 'resource2'}))
mock_get_resources.return_value = [res1, res2]
project_measures = measurements.get_measurements(
'123', str(start), str(end)
)
self.assertEqual(
{
'start': str(start),
'end': str(end),
'project_name': 'fake_name',
'project_id': '123',
'resources': {
'111': {
'name': 'resource1',
'services': [
{'name': 'srv1', 'volume': 10, 'unit': 'byte'}
]
},
'222': {
'name': 'resource2',
'services': [
{'name': 'srv2', 'volume': 20, 'unit': 'byte'}
]
}
}
},
project_measures
)

View File

@ -3,7 +3,7 @@
# from above list. And make sure the versions are sync with OpenStack global
# requirements.
Babel==1.3
Babel>=2.3.4,!=2.4.0 # BSD
Flask<1.0,>=0.10 # BSD
pbr>=1.6 # Apache-2.0
six>=1.9.0 # MIT