Permalink
Browse files

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
  • Loading branch information...
1 parent de9813c commit c3b043be0e2309197776195ceb82d190aaa9046b @crobinso crobinso committed Jan 22, 2012
Showing with 178 additions and 0 deletions.
  1. +1 −0 AUTHORS
  2. +1 −0 README.rst
  3. +2 −0 novaclient/v1_1/client.py
  4. +44 −0 novaclient/v1_1/shell.py
  5. +48 −0 novaclient/v1_1/usage.py
  6. +39 −0 tests/v1_1/fakes.py
  7. +8 −0 tests/v1_1/test_shell.py
  8. +35 −0 tests/v1_1/test_usage.py
View
@@ -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>
View
@@ -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 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 @@ def __init__(self, username, api_key, project_id, auth_url,
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)
View
@@ -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)
View
@@ -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")
View
@@ -643,3 +643,42 @@ def post_os_security_group_rules(self, body, **kw):
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}})
View
@@ -320,3 +320,11 @@ def test_dns_list(self):
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')
View
@@ -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))

0 comments on commit c3b043b

Please sign in to comment.