Actually normalize nova usage data
Turns out usage reports are empty when there is no usage - so direct passthrough is not so much a thing. Fix it. Change-Id: I6a2f2e737f792ba74a191d688b3380dc333e34fe
This commit is contained in:
parent
71322c7bbc
commit
60ce27ea81
@ -228,6 +228,58 @@ Limits and current usage for a project in Nova
|
||||
total_server_groups_used=int(),
|
||||
properties=dict())
|
||||
|
||||
ComputeUsage
|
||||
------------
|
||||
|
||||
Current usage for a project in Nova
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ComputeUsage = dict(
|
||||
location=Location(),
|
||||
started_at=str(),
|
||||
stopped_at=str(),
|
||||
server_usages=list(),
|
||||
max_personality=int(),
|
||||
max_personality_size=int(),
|
||||
max_server_group_members=int(),
|
||||
max_server_groups=int(),
|
||||
max_server_meta=int(),
|
||||
max_total_cores=int(),
|
||||
max_total_instances=int(),
|
||||
max_total_keypairs=int(),
|
||||
max_total_ram_size=int(),
|
||||
total_cores_used=int(),
|
||||
total_hours=int(),
|
||||
total_instances_used=int(),
|
||||
total_local_gb_usage=int(),
|
||||
total_memory_mb_usage=int(),
|
||||
total_ram_used=int(),
|
||||
total_server_groups_used=int(),
|
||||
total_vcpus_usage=int(),
|
||||
properties=dict())
|
||||
|
||||
ServerUsage
|
||||
-----------
|
||||
|
||||
Current usage for a server in Nova
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ComputeUsage = dict(
|
||||
started_at=str(),
|
||||
ended_at=str(),
|
||||
flavor=str(),
|
||||
hours=int(),
|
||||
instance_id=str(),
|
||||
local_gb=int(),
|
||||
memory_mb=int(),
|
||||
name=str(),
|
||||
state=str(),
|
||||
uptime=int(),
|
||||
vcpus=int(),
|
||||
properties=dict())
|
||||
|
||||
Floating IP
|
||||
-----------
|
||||
|
||||
|
@ -762,8 +762,10 @@ class Normalizer(object):
|
||||
ret.setdefault(key, val)
|
||||
return ret
|
||||
|
||||
def _normalize_usage(self, usage):
|
||||
""" Normalize a usage object """
|
||||
def _normalize_compute_usage(self, usage):
|
||||
""" Normalize a compute usage object """
|
||||
|
||||
usage = usage.copy()
|
||||
|
||||
# Discard noise
|
||||
usage.pop('links', None)
|
||||
@ -771,5 +773,66 @@ class Normalizer(object):
|
||||
usage.pop('HUMAN_ID', None)
|
||||
usage.pop('human_id', None)
|
||||
usage.pop('request_ids', None)
|
||||
project_id = usage.pop('tenant_id', None)
|
||||
|
||||
return munch.Munch(usage)
|
||||
ret = munch.Munch(
|
||||
location=self._get_current_location(project_id=project_id),
|
||||
)
|
||||
for key in (
|
||||
'max_personality',
|
||||
'max_personality_size',
|
||||
'max_server_group_members',
|
||||
'max_server_groups',
|
||||
'max_server_meta',
|
||||
'max_total_cores',
|
||||
'max_total_instances',
|
||||
'max_total_keypairs',
|
||||
'max_total_ram_size',
|
||||
'total_cores_used',
|
||||
'total_hours',
|
||||
'total_instances_used',
|
||||
'total_local_gb_usage',
|
||||
'total_memory_mb_usage',
|
||||
'total_ram_used',
|
||||
'total_server_groups_used',
|
||||
'total_vcpus_usage'):
|
||||
ret[key] = usage.pop(key, 0)
|
||||
ret['started_at'] = usage.pop('start')
|
||||
ret['stopped_at'] = usage.pop('stop')
|
||||
ret['server_usages'] = self._normalize_server_usages(
|
||||
usage.pop('server_usages', []))
|
||||
ret['properties'] = usage
|
||||
return ret
|
||||
|
||||
def _normalize_server_usage(self, server_usage):
|
||||
""" Normalize a server usage object """
|
||||
|
||||
server_usage = server_usage.copy()
|
||||
# TODO(mordred) Right now there is already a location on the usage
|
||||
# object. Including one here seems verbose.
|
||||
server_usage.pop('tenant_id')
|
||||
ret = munch.Munch()
|
||||
|
||||
ret['ended_at'] = server_usage.pop('ended_at', None)
|
||||
ret['started_at'] = server_usage.pop('started_at', None)
|
||||
for key in (
|
||||
'flavor',
|
||||
'instance_id',
|
||||
'name',
|
||||
'state'):
|
||||
ret[key] = server_usage.pop(key, '')
|
||||
for key in (
|
||||
'hours',
|
||||
'local_gb',
|
||||
'memory_mb',
|
||||
'uptime',
|
||||
'vcpus'):
|
||||
ret[key] = server_usage.pop(key, 0)
|
||||
ret['properties'] = server_usage
|
||||
return ret
|
||||
|
||||
def _normalize_server_usages(self, server_usages):
|
||||
ret = []
|
||||
for server_usage in server_usages:
|
||||
ret.append(self._normalize_server_usage(server_usage))
|
||||
return ret
|
||||
|
@ -10,6 +10,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import datetime
|
||||
import jsonpatch
|
||||
|
||||
from ironicclient import client as ironic_client
|
||||
@ -2111,12 +2112,12 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
|
||||
except nova_exceptions.BadRequest:
|
||||
raise OpenStackCloudException("nova client call failed")
|
||||
|
||||
def get_compute_usage(self, name_or_id, start, end):
|
||||
def get_compute_usage(self, name_or_id, start, end=None):
|
||||
""" Get usage for a specific project
|
||||
|
||||
:param name_or_id: project name or id
|
||||
:param start: :class:`datetime.datetime` Start date in UTC
|
||||
:param end: :class:`datetime.datetime` End date in UTCs
|
||||
:param end: :class:`datetime.datetime` End date in UTC. Defaults to now
|
||||
:raises: OpenStackCloudException if it's not a valid project
|
||||
|
||||
:returns: Munch object with the usage
|
||||
@ -2125,6 +2126,8 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
|
||||
if not proj:
|
||||
raise OpenStackCloudException("project does not exist: {}".format(
|
||||
name=proj.id))
|
||||
if not end:
|
||||
end = datetime.datetime.now()
|
||||
|
||||
with _utils.shade_exceptions(
|
||||
"Unable to get resources usage for project: {name}".format(
|
||||
@ -2132,7 +2135,7 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
|
||||
usage = self.manager.submit_task(
|
||||
_tasks.NovaUsageGet(tenant_id=proj.id, start=start, end=end))
|
||||
|
||||
return self._normalize_usage(usage)
|
||||
return self._normalize_compute_usage(usage)
|
||||
|
||||
def set_volume_quotas(self, name_or_id, **kwargs):
|
||||
""" Set a volume quota in a project
|
||||
|
@ -25,11 +25,13 @@ from shade.tests.functional import base
|
||||
|
||||
class TestUsage(base.BaseFunctionalTestCase):
|
||||
|
||||
def test_get_usage(self):
|
||||
'''Test quotas functionality'''
|
||||
usage = self.operator_cloud.get_compute_usage('demo',
|
||||
datetime.datetime.now(),
|
||||
datetime.datetime.now())
|
||||
def test_get_compute_usage(self):
|
||||
'''Test usage functionality'''
|
||||
start = datetime.datetime.now() - datetime.timedelta(seconds=5)
|
||||
usage = self.operator_cloud.get_compute_usage('demo', start)
|
||||
self.add_info_on_exception('usage', usage)
|
||||
self.assertIsNotNone(usage)
|
||||
self.assertTrue(hasattr(usage, 'total_hours'))
|
||||
self.assertIn('total_hours', usage)
|
||||
self.assertIn('started_at', usage)
|
||||
self.assertEqual(start.isoformat(), usage['started_at'])
|
||||
self.assertIn('location', usage)
|
||||
|
Loading…
x
Reference in New Issue
Block a user