Merge "compute: Add support for os-simple-tenant-usages API"
This commit is contained in:
commit
6469429498
@ -31,6 +31,7 @@ from openstack.compute.v2 import server_ip
|
||||
from openstack.compute.v2 import server_migration as _server_migration
|
||||
from openstack.compute.v2 import server_remote_console as _src
|
||||
from openstack.compute.v2 import service as _service
|
||||
from openstack.compute.v2 import usage as _usage
|
||||
from openstack.compute.v2 import volume_attachment as _volume_attachment
|
||||
from openstack import exceptions
|
||||
from openstack.identity.v3 import project as _project
|
||||
@ -609,10 +610,8 @@ class Proxy(proxy.Proxy):
|
||||
:class:`~openstack.compute.v2.limits.RateLimits`
|
||||
:rtype: :class:`~openstack.compute.v2.limits.Limits`
|
||||
"""
|
||||
res = self._get_resource(
|
||||
limits.Limits, None)
|
||||
return res.fetch(
|
||||
self, **query)
|
||||
res = self._get_resource(limits.Limits, None)
|
||||
return res.fetch(self, **query)
|
||||
|
||||
# ========== Servers ==========
|
||||
|
||||
@ -1865,6 +1864,46 @@ class Proxy(proxy.Proxy):
|
||||
return self._get(_server_diagnostics.ServerDiagnostics,
|
||||
server_id=server_id, requires_id=False)
|
||||
|
||||
# ========== Project usage ============
|
||||
|
||||
def usages(self, start=None, end=None, **query):
|
||||
"""Get project usages.
|
||||
|
||||
:param datetime.datetime start: Usage range start date.
|
||||
:param datetime.datetime end: Usage range end date.
|
||||
:param dict query: Additional query parameters to use.
|
||||
:returns: A list of compute ``Usage`` objects.
|
||||
"""
|
||||
if start is not None:
|
||||
query['start'] = start
|
||||
|
||||
if end is not None:
|
||||
query['end'] = end
|
||||
|
||||
return self._list(_usage.Usage, **query)
|
||||
|
||||
def get_usage(self, project, start=None, end=None, **query):
|
||||
"""Get usage for a single project.
|
||||
|
||||
:param project: ID or instance of
|
||||
:class:`~openstack.identity.project.Project` of the project for
|
||||
which the usage should be retrieved.
|
||||
:param datetime.datetime start: Usage range start date.
|
||||
:param datetime.datetime end: Usage range end date.
|
||||
:param dict query: Additional query parameters to use.
|
||||
:returns: A compute ``Usage`` object.
|
||||
"""
|
||||
project = self._get_resource(_project.Project, project)
|
||||
|
||||
if start is not None:
|
||||
query['start'] = start
|
||||
|
||||
if end is not None:
|
||||
query['end'] = end
|
||||
|
||||
res = self._get_resource(_usage.Usage, project.id)
|
||||
return res.fetch(self, **query)
|
||||
|
||||
# ========== Server consoles ==========
|
||||
|
||||
def create_server_remote_console(self, server, **attrs):
|
||||
@ -1953,11 +1992,9 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
project = self._get_resource(_project.Project, project)
|
||||
res = self._get_resource(
|
||||
_quota_set.QuotaSet, None, project_id=project.id)
|
||||
if not query:
|
||||
query = {}
|
||||
return res.fetch(
|
||||
self, usage=usage, **query)
|
||||
_quota_set.QuotaSet, None, project_id=project.id,
|
||||
)
|
||||
return res.fetch(self, usage=usage, **query)
|
||||
|
||||
def get_quota_set_defaults(self, project):
|
||||
"""Show QuotaSet defaults for the project
|
||||
@ -1972,9 +2009,9 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
project = self._get_resource(_project.Project, project)
|
||||
res = self._get_resource(
|
||||
_quota_set.QuotaSet, None, project_id=project.id)
|
||||
return res.fetch(
|
||||
self, base_path='/os-quota-sets/defaults')
|
||||
_quota_set.QuotaSet, None, project_id=project.id,
|
||||
)
|
||||
return res.fetch(self, base_path='/os-quota-sets/defaults')
|
||||
|
||||
def revert_quota_set(self, project, **query):
|
||||
"""Reset Quota for the project/user.
|
||||
|
102
openstack/compute/v2/usage.py
Normal file
102
openstack/compute/v2/usage.py
Normal file
@ -0,0 +1,102 @@
|
||||
# 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 openstack import resource
|
||||
|
||||
|
||||
class ServerUsage(resource.Resource):
|
||||
resource_key = None
|
||||
resources_key = None
|
||||
|
||||
# Capabilities
|
||||
allow_create = False
|
||||
allow_fetch = False
|
||||
allow_delete = False
|
||||
allow_list = False
|
||||
allow_commit = False
|
||||
|
||||
# Properties
|
||||
#: The duration that the server exists (in hours).
|
||||
hours = resource.Body('hours')
|
||||
#: The display name of a flavor.
|
||||
flavor = resource.Body('flavor')
|
||||
#: The UUID of the server.
|
||||
instance_id = resource.Body('instance_id')
|
||||
#: The server name.
|
||||
name = resource.Body('name')
|
||||
#: The UUID of the project in a multi-tenancy cloud.
|
||||
project_id = resource.Body('tenant_id')
|
||||
#: The memory size of the server (in MiB).
|
||||
memory_mb = resource.Body('memory_mb')
|
||||
#: The sum of the root disk size of the server and the ephemeral disk size
|
||||
#: of it (in GiB).
|
||||
local_gb = resource.Body('local_gb')
|
||||
#: The number of virtual CPUs that the server uses.
|
||||
vcpus = resource.Body('vcpus')
|
||||
#: The date and time when the server was launched.
|
||||
started_at = resource.Body('started_at')
|
||||
#: The date and time when the server was deleted.
|
||||
ended_at = resource.Body('ended_at')
|
||||
#: The VM state.
|
||||
state = resource.Body('state')
|
||||
#: The uptime of the server.
|
||||
uptime = resource.Body('uptime')
|
||||
|
||||
|
||||
class Usage(resource.Resource):
|
||||
resource_key = 'tenant_usage'
|
||||
resources_key = 'tenant_usages'
|
||||
base_path = '/os-simple-tenant-usage'
|
||||
|
||||
# Capabilities
|
||||
allow_create = False
|
||||
allow_fetch = True
|
||||
allow_delete = False
|
||||
allow_list = True
|
||||
allow_commit = False
|
||||
|
||||
# TODO(stephenfin): Add 'start', 'end'. These conflict with the body
|
||||
# responses though.
|
||||
_query_mapping = resource.QueryParameters(
|
||||
"detailed",
|
||||
"limit",
|
||||
"marker",
|
||||
"start",
|
||||
"end",
|
||||
)
|
||||
|
||||
# Properties
|
||||
#: The UUID of the project in a multi-tenancy cloud.
|
||||
project_id = resource.Body('tenant_id')
|
||||
#: A list of the server usage objects.
|
||||
server_usages = resource.Body(
|
||||
'server_usages', type=list, list_type=ServerUsage,
|
||||
)
|
||||
#: Multiplying the server disk size (in GiB) by hours the server exists,
|
||||
#: and then adding that all together for each server.
|
||||
total_local_gb_usage = resource.Body('total_local_gb_usage')
|
||||
#: Multiplying the number of virtual CPUs of the server by hours the server
|
||||
#: exists, and then adding that all together for each server.
|
||||
total_vcpus_usage = resource.Body('total_vcpus_usage')
|
||||
#: Multiplying the server memory size (in MiB) by hours the server exists,
|
||||
#: and then adding that all together for each server.
|
||||
total_memory_mb_usage = resource.Body('total_memory_mb_usage')
|
||||
#: The total duration that servers exist (in hours).
|
||||
total_hours = resource.Body('total_hours')
|
||||
#: The beginning time to calculate usage statistics on compute and storage
|
||||
#: resources.
|
||||
start = resource.Body('start')
|
||||
#: The ending time to calculate usage statistics on compute and storage
|
||||
#: resources.
|
||||
stop = resource.Body('stop')
|
||||
|
||||
_max_microversion = '2.75'
|
@ -10,6 +10,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
from unittest import mock
|
||||
|
||||
from openstack.compute.v2 import _proxy
|
||||
@ -30,6 +31,7 @@ from openstack.compute.v2 import server_ip
|
||||
from openstack.compute.v2 import server_migration
|
||||
from openstack.compute.v2 import server_remote_console
|
||||
from openstack.compute.v2 import service
|
||||
from openstack.compute.v2 import usage
|
||||
from openstack import resource
|
||||
from openstack.tests.unit import test_proxy_base
|
||||
|
||||
@ -1105,6 +1107,43 @@ class TestCompute(TestComputeProxy):
|
||||
method_args=["value", {'id': 'id', 'name': 'sg'}],
|
||||
expected_args=[self.proxy, 'sg'])
|
||||
|
||||
def test_usages(self):
|
||||
self.verify_list(self.proxy.usages, usage.Usage)
|
||||
|
||||
def test_usages__with_kwargs(self):
|
||||
now = datetime.datetime.utcnow()
|
||||
start = now - datetime.timedelta(weeks=4)
|
||||
end = end = now + datetime.timedelta(days=1)
|
||||
self.verify_list(
|
||||
self.proxy.usages,
|
||||
usage.Usage,
|
||||
method_kwargs={'start': start, 'end': end},
|
||||
expected_kwargs={'start': start, 'end': end},
|
||||
)
|
||||
|
||||
def test_get_usage(self):
|
||||
self._verify(
|
||||
"openstack.compute.v2.usage.Usage.fetch",
|
||||
self.proxy.get_usage,
|
||||
method_args=['value'],
|
||||
method_kwargs={},
|
||||
expected_args=[self.proxy],
|
||||
expected_kwargs={},
|
||||
)
|
||||
|
||||
def test_get_usage__with_kwargs(self):
|
||||
now = datetime.datetime.utcnow()
|
||||
start = now - datetime.timedelta(weeks=4)
|
||||
end = end = now + datetime.timedelta(days=1)
|
||||
self._verify(
|
||||
"openstack.compute.v2.usage.Usage.fetch",
|
||||
self.proxy.get_usage,
|
||||
method_args=['value'],
|
||||
method_kwargs={'start': start, 'end': end},
|
||||
expected_args=[self.proxy],
|
||||
expected_kwargs={'start': start, 'end': end},
|
||||
)
|
||||
|
||||
def test_create_server_remote_console(self):
|
||||
self.verify_create(
|
||||
self.proxy.create_server_remote_console,
|
||||
|
99
openstack/tests/unit/compute/v2/test_usage.py
Normal file
99
openstack/tests/unit/compute/v2/test_usage.py
Normal file
@ -0,0 +1,99 @@
|
||||
# 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 openstack.compute.v2 import usage
|
||||
from openstack.tests.unit import base
|
||||
|
||||
|
||||
EXAMPLE = {
|
||||
"tenant_id": "781c9299e68d4b7c80ef52712889647f",
|
||||
"server_usages": [
|
||||
{
|
||||
"hours": 79.51840531333333,
|
||||
"flavor": "m1.tiny",
|
||||
"instance_id": "76638c30-d199-4c2e-8154-7dea963bfe2f",
|
||||
"name": "test-server",
|
||||
"tenant_id": "781c9299e68d4b7c80ef52712889647f",
|
||||
"memory_mb": 512,
|
||||
"local_gb": 1,
|
||||
"vcpus": 1,
|
||||
"started_at": "2022-05-16T10:35:31.000000",
|
||||
"ended_at": None,
|
||||
"state": "active",
|
||||
"uptime": 286266,
|
||||
}
|
||||
],
|
||||
"total_local_gb_usage": 79.51840531333333,
|
||||
"total_vcpus_usage": 79.51840531333333,
|
||||
"total_memory_mb_usage": 40713.423520426666,
|
||||
"total_hours": 79.51840531333333,
|
||||
"start": "2022-04-21T18:06:47.064959",
|
||||
"stop": "2022-05-19T18:06:37.259128",
|
||||
}
|
||||
|
||||
|
||||
class TestUsage(base.TestCase):
|
||||
def test_basic(self):
|
||||
sot = usage.Usage()
|
||||
self.assertEqual('tenant_usage', sot.resource_key)
|
||||
self.assertEqual('tenant_usages', sot.resources_key)
|
||||
self.assertEqual('/os-simple-tenant-usage', sot.base_path)
|
||||
self.assertTrue(sot.allow_fetch)
|
||||
self.assertTrue(sot.allow_list)
|
||||
|
||||
def test_make_it(self):
|
||||
sot = usage.Usage(**EXAMPLE)
|
||||
|
||||
self.assertEqual(EXAMPLE['tenant_id'], sot.project_id)
|
||||
self.assertEqual(
|
||||
EXAMPLE['total_local_gb_usage'],
|
||||
sot.total_local_gb_usage,
|
||||
)
|
||||
self.assertEqual(EXAMPLE['total_vcpus_usage'], sot.total_vcpus_usage)
|
||||
self.assertEqual(
|
||||
EXAMPLE['total_memory_mb_usage'],
|
||||
sot.total_memory_mb_usage,
|
||||
)
|
||||
self.assertEqual(EXAMPLE['total_hours'], sot.total_hours)
|
||||
self.assertEqual(EXAMPLE['start'], sot.start)
|
||||
self.assertEqual(EXAMPLE['stop'], sot.stop)
|
||||
|
||||
# now do the embedded objects
|
||||
self.assertIsInstance(sot.server_usages, list)
|
||||
self.assertEqual(1, len(sot.server_usages))
|
||||
|
||||
ssot = sot.server_usages[0]
|
||||
self.assertIsInstance(ssot, usage.ServerUsage)
|
||||
self.assertEqual(EXAMPLE['server_usages'][0]['hours'], ssot.hours)
|
||||
self.assertEqual(EXAMPLE['server_usages'][0]['flavor'], ssot.flavor)
|
||||
self.assertEqual(
|
||||
EXAMPLE['server_usages'][0]['instance_id'], ssot.instance_id
|
||||
)
|
||||
self.assertEqual(EXAMPLE['server_usages'][0]['name'], ssot.name)
|
||||
self.assertEqual(
|
||||
EXAMPLE['server_usages'][0]['tenant_id'], ssot.project_id
|
||||
)
|
||||
self.assertEqual(
|
||||
EXAMPLE['server_usages'][0]['memory_mb'], ssot.memory_mb
|
||||
)
|
||||
self.assertEqual(
|
||||
EXAMPLE['server_usages'][0]['local_gb'], ssot.local_gb
|
||||
)
|
||||
self.assertEqual(EXAMPLE['server_usages'][0]['vcpus'], ssot.vcpus)
|
||||
self.assertEqual(
|
||||
EXAMPLE['server_usages'][0]['started_at'], ssot.started_at
|
||||
)
|
||||
self.assertEqual(
|
||||
EXAMPLE['server_usages'][0]['ended_at'], ssot.ended_at
|
||||
)
|
||||
self.assertEqual(EXAMPLE['server_usages'][0]['state'], ssot.state)
|
||||
self.assertEqual(EXAMPLE['server_usages'][0]['uptime'], ssot.uptime)
|
Loading…
Reference in New Issue
Block a user