Add a 'usage' module and 'usage-list' cli command
This module talks to the nova extenstion os-simple-tenant-usage, replacing the openstackx module currently used by horizon. v2: Fix some pep8 and style violations v4: Have usage-list default to including todays usage v5: Fix a HACKING violation Fix rebase conflicts Change-Id: Ica0b128c7b807b839abf23b4026e48bbee08b1be
This commit is contained in:
parent
de9813c6c5
commit
c3b043be0e
1
AUTHORS
1
AUTHORS
@ -8,6 +8,7 @@ Brian Waldon <brian.waldon@rackspace.com>
|
||||
Chmouel Boudjnah <chmouel.boudjnah@rackspace.co.uk>
|
||||
Chris Behrens <cbehrens+github@codestud.com>
|
||||
Christopher MacGown <ignoti+github@gmail.com>
|
||||
Cole Robinson <crobinso@redhat.com>
|
||||
Dan Wendlandt <dan@nicira.com>
|
||||
Dean Troyer <dtroyer@gmail.com>
|
||||
Ed Leafe <ed@leafe.com>
|
||||
|
@ -135,6 +135,7 @@ You'll find complete documentation on the shell by running
|
||||
suspend Suspend a server.
|
||||
unpause Unpause a server.
|
||||
unrescue Unrescue a server.
|
||||
usage-list List usage data for all tenants
|
||||
volume-attach Attach a volume to a server.
|
||||
volume-create Add a new volume.
|
||||
volume-delete Remove a volume.
|
||||
|
@ -10,6 +10,7 @@ from novaclient.v1_1 import quotas
|
||||
from novaclient.v1_1 import security_group_rules
|
||||
from novaclient.v1_1 import security_groups
|
||||
from novaclient.v1_1 import servers
|
||||
from novaclient.v1_1 import usage
|
||||
from novaclient.v1_1 import virtual_interfaces
|
||||
from novaclient.v1_1 import volumes
|
||||
from novaclient.v1_1 import volume_snapshots
|
||||
@ -57,6 +58,7 @@ class Client(object):
|
||||
self.security_groups = security_groups.SecurityGroupManager(self)
|
||||
self.security_group_rules = \
|
||||
security_group_rules.SecurityGroupRuleManager(self)
|
||||
self.usage = usage.UsageManager(self)
|
||||
self.virtual_interfaces = \
|
||||
virtual_interfaces.VirtualInterfaceManager(self)
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
import getpass
|
||||
import os
|
||||
|
||||
@ -1275,3 +1276,46 @@ def do_rate_limits(cs, args):
|
||||
limits = cs.limits.get().rate
|
||||
columns = ['Verb', 'URI', 'Value', 'Remain', 'Unit', 'Next_Available']
|
||||
utils.print_list(limits, columns)
|
||||
|
||||
|
||||
@utils.arg('--start', metavar='<start>',
|
||||
help='Usage range start date ex 2012-01-20 (default: 4 weeks ago)',
|
||||
default=None)
|
||||
@utils.arg('--end', metavar='<end>',
|
||||
help='Usage range end date, ex 2012-01-20 (default: tomorrow) ',
|
||||
default=None)
|
||||
def do_usage_list(cs, args):
|
||||
"""List usage data for all tenants"""
|
||||
dateformat = "%Y-%m-%d"
|
||||
rows = ["Tenant ID", "Instances", "RAM MB-Hours", "CPU Hours",
|
||||
"Disk GB-Hours"]
|
||||
|
||||
if args.start:
|
||||
start = datetime.datetime.strptime(args.start, dateformat)
|
||||
else:
|
||||
start = (datetime.datetime.today() -
|
||||
datetime.timedelta(weeks=4))
|
||||
|
||||
if args.end:
|
||||
end = datetime.datetime.strptime(args.end, dateformat)
|
||||
else:
|
||||
end = datetime.datetime.tomorrow()
|
||||
|
||||
def simplify_usage(u):
|
||||
simplerows = map(lambda x: x.lower().replace(" ", "_"), rows)
|
||||
|
||||
setattr(u, simplerows[0], u.tenant_id)
|
||||
setattr(u, simplerows[1], "%d" % len(u.server_usages))
|
||||
setattr(u, simplerows[2], "%.2f" % u.total_memory_mb_usage)
|
||||
setattr(u, simplerows[3], "%.2f" % u.total_vcpus_usage)
|
||||
setattr(u, simplerows[4], "%.2f" % u.total_local_gb_usage)
|
||||
|
||||
usage_list = cs.usage.list(start, end, detailed=True)
|
||||
|
||||
print "Usage from %s to %s:" % (start.strftime(dateformat),
|
||||
end.strftime(dateformat))
|
||||
|
||||
for usage in usage_list:
|
||||
simplify_usage(usage)
|
||||
|
||||
utils.print_list(usage_list, rows)
|
||||
|
48
novaclient/v1_1/usage.py
Normal file
48
novaclient/v1_1/usage.py
Normal file
@ -0,0 +1,48 @@
|
||||
"""
|
||||
Usage interface.
|
||||
"""
|
||||
|
||||
from novaclient import base
|
||||
|
||||
|
||||
class Usage(base.Resource):
|
||||
"""
|
||||
Usage contains infomartion about a tenants physical resource usage
|
||||
"""
|
||||
def __repr__(self):
|
||||
return "<ComputeUsage>"
|
||||
|
||||
|
||||
class UsageManager(base.ManagerWithFind):
|
||||
"""
|
||||
Manage :class:`Usage` resources.
|
||||
"""
|
||||
resource_class = Usage
|
||||
|
||||
def list(self, start, end, detailed=False):
|
||||
"""
|
||||
Get usage for all tenants
|
||||
|
||||
:param start: :class:`datetime.datetime` Start date
|
||||
:param end: :class:`datetime.datetime` End date
|
||||
:param detailed: Whether to include information about each
|
||||
instance whose usage is part of the report
|
||||
:rtype: list of :class:`Usage`.
|
||||
"""
|
||||
return self._list(
|
||||
"/os-simple-tenant-usage?start=%s&end=%s&detailed=%s" %
|
||||
(start.isoformat(), end.isoformat(), int(bool(detailed))),
|
||||
"tenant_usages")
|
||||
|
||||
def get(self, tenant_id, start, end):
|
||||
"""
|
||||
Get usage for a specific tenant.
|
||||
|
||||
:param tenant_id: Tenant ID to fetch usage for
|
||||
:param start: :class:`datetime.datetime` Start date
|
||||
:param end: :class:`datetime.datetime` End date
|
||||
:rtype: :class:`Usage`
|
||||
"""
|
||||
return self._get("/os-simple-tenant-usage/%s?start=%s&end=%s" %
|
||||
(tenant_id, start.isoformat(), end.isoformat()),
|
||||
"tenant_usage")
|
@ -643,3 +643,42 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
r = {'security_group_rule':
|
||||
self.get_os_security_group_rules()[1]['security_group_rules'][0]}
|
||||
return (202, r)
|
||||
|
||||
#
|
||||
# Tenant Usage
|
||||
#
|
||||
def get_os_simple_tenant_usage(self, **kw):
|
||||
return (200, {u'tenant_usages': [{
|
||||
u'total_memory_mb_usage': 25451.762807466665,
|
||||
u'total_vcpus_usage': 49.71047423333333,
|
||||
u'total_hours': 49.71047423333333,
|
||||
u'tenant_id': u'7b0a1d73f8fb41718f3343c207597869',
|
||||
u'stop': u'2012-01-22 19:48:41.750722',
|
||||
u'server_usages': [{
|
||||
u'hours': 49.71047423333333,
|
||||
u'uptime': 27035, u'local_gb': 0, u'ended_at': None,
|
||||
u'name': u'f15image1',
|
||||
u'tenant_id': u'7b0a1d73f8fb41718f3343c207597869',
|
||||
u'vcpus': 1, u'memory_mb': 512, u'state': u'active',
|
||||
u'flavor': u'm1.tiny',
|
||||
u'started_at': u'2012-01-20 18:06:06.479998'}],
|
||||
u'start': u'2011-12-25 19:48:41.750687',
|
||||
u'total_local_gb_usage': 0.0}]})
|
||||
|
||||
def get_os_simple_tenant_usage_tenantfoo(self, **kw):
|
||||
return (200, {u'tenant_usage': {
|
||||
u'total_memory_mb_usage': 25451.762807466665,
|
||||
u'total_vcpus_usage': 49.71047423333333,
|
||||
u'total_hours': 49.71047423333333,
|
||||
u'tenant_id': u'7b0a1d73f8fb41718f3343c207597869',
|
||||
u'stop': u'2012-01-22 19:48:41.750722',
|
||||
u'server_usages': [{
|
||||
u'hours': 49.71047423333333,
|
||||
u'uptime': 27035, u'local_gb': 0, u'ended_at': None,
|
||||
u'name': u'f15image1',
|
||||
u'tenant_id': u'7b0a1d73f8fb41718f3343c207597869',
|
||||
u'vcpus': 1, u'memory_mb': 512, u'state': u'active',
|
||||
u'flavor': u'm1.tiny',
|
||||
u'started_at': u'2012-01-20 18:06:06.479998'}],
|
||||
u'start': u'2011-12-25 19:48:41.750687',
|
||||
u'total_local_gb_usage': 0.0}})
|
||||
|
@ -320,3 +320,11 @@ class ShellTest(utils.TestCase):
|
||||
def test_dns_zones(self):
|
||||
self.run_command('dns-zones')
|
||||
self.assert_called('GET', '/os-floating-ip-dns')
|
||||
|
||||
def test_usage_list(self):
|
||||
self.run_command('usage-list --start 2000-01-20 --end 2005-02-01')
|
||||
self.assert_called('GET',
|
||||
'/os-simple-tenant-usage?' +
|
||||
'start=2000-01-20T00:00:00&' +
|
||||
'end=2005-02-01T00:00:00&' +
|
||||
'detailed=1')
|
||||
|
35
tests/v1_1/test_usage.py
Normal file
35
tests/v1_1/test_usage.py
Normal file
@ -0,0 +1,35 @@
|
||||
import datetime
|
||||
|
||||
from novaclient.v1_1 import usage
|
||||
from tests import utils
|
||||
from tests.v1_1 import fakes
|
||||
|
||||
|
||||
cs = fakes.FakeClient()
|
||||
|
||||
|
||||
class UsageTest(utils.TestCase):
|
||||
|
||||
def test_usage_list(self, detailed=False):
|
||||
now = datetime.datetime.now()
|
||||
usages = cs.usage.list(now, now, detailed)
|
||||
|
||||
cs.assert_called('GET',
|
||||
"/os-simple-tenant-usage?" +
|
||||
("start=%s&" % now.isoformat()) +
|
||||
("end=%s&" % now.isoformat()) +
|
||||
("detailed=%s" % int(bool(detailed))))
|
||||
[self.assertTrue(isinstance(u, usage.Usage)) for u in usages]
|
||||
|
||||
def test_usage_list_detailed(self):
|
||||
self.test_usage_list(True)
|
||||
|
||||
def test_usage_get(self):
|
||||
now = datetime.datetime.now()
|
||||
u = cs.usage.get("tenantfoo", now, now)
|
||||
|
||||
cs.assert_called('GET',
|
||||
"/os-simple-tenant-usage/tenantfoo?" +
|
||||
("start=%s&" % now.isoformat()) +
|
||||
("end=%s" % now.isoformat()))
|
||||
self.assertTrue(isinstance(u, usage.Usage))
|
Loading…
Reference in New Issue
Block a user