summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--novaclient/base.py6
-rw-r--r--novaclient/v1_1/client.py6
-rw-r--r--novaclient/v1_1/limits.py79
-rw-r--r--novaclient/v1_1/shell.py14
-rw-r--r--setup.py2
-rw-r--r--tests/v1_1/fakes.py83
-rw-r--r--tests/v1_1/test_limits.py52
7 files changed, 196 insertions, 46 deletions
diff --git a/novaclient/base.py b/novaclient/base.py
index 088aa5ed..9b35ffed 100644
--- a/novaclient/base.py
+++ b/novaclient/base.py
@@ -268,7 +268,11 @@ class Resource(object):
def _add_details(self, info):
for (k, v) in info.iteritems():
- setattr(self, k, v)
+ try:
+ setattr(self, k, v)
+ except AttributeError:
+ # In this case we already defined the attribute on the class
+ pass
def __getattr__(self, k):
if k not in self.__dict__:
diff --git a/novaclient/v1_1/client.py b/novaclient/v1_1/client.py
index 2e00345c..cf82b1cf 100644
--- a/novaclient/v1_1/client.py
+++ b/novaclient/v1_1/client.py
@@ -3,10 +3,11 @@ from novaclient.v1_1 import flavors
from novaclient.v1_1 import floating_ips
from novaclient.v1_1 import images
from novaclient.v1_1 import keypairs
+from novaclient.v1_1 import limits
+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 quotas
from novaclient.v1_1 import volumes
from novaclient.v1_1 import volume_snapshots
from novaclient.v1_1 import zones
@@ -37,11 +38,12 @@ class Client(object):
# know it's not being used as keyword argument
password = api_key
self.flavors = flavors.FlavorManager(self)
- self.floating_ips = floating_ips.FloatingIPManager(self)
self.images = images.ImageManager(self)
+ self.limits = limits.LimitsManager(self)
self.servers = servers.ServerManager(self)
# extensions
+ self.floating_ips = floating_ips.FloatingIPManager(self)
self.volumes = volumes.VolumeManager(self)
self.volume_snapshots = volume_snapshots.SnapshotManager(self)
self.keypairs = keypairs.KeypairManager(self)
diff --git a/novaclient/v1_1/limits.py b/novaclient/v1_1/limits.py
new file mode 100644
index 00000000..75bf5416
--- /dev/null
+++ b/novaclient/v1_1/limits.py
@@ -0,0 +1,79 @@
+# Copyright 2011 OpenStack LLC.
+
+from novaclient import base
+
+
+class Limits(base.Resource):
+ """A collection of RateLimit and AbsoluteLimit objects"""
+
+ def __repr__(self):
+ return "<Limits>"
+
+ @property
+ def absolute(self):
+ for (name, value) in self._info['absolute'].items():
+ yield AbsoluteLimit(name, value)
+
+ @property
+ def rate(self):
+ for group in self._info['rate']:
+ uri = group['uri']
+ regex = group['regex']
+ for rate in group['limit']:
+ yield RateLimit(rate['verb'], uri, regex, rate['value'],
+ rate['remaining'], rate['unit'],
+ rate['next-available'])
+
+
+class RateLimit(object):
+ """Data model that represents a flattened view of a single rate limit"""
+
+ def __init__(self, verb, uri, regex, value, remain,
+ unit, next_available):
+ self.verb = verb
+ self.uri = uri
+ self.regex = regex
+ self.value = value
+ self.remain = remain
+ self.unit = unit
+ self.next_available = next_available
+
+ def __eq__(self, other):
+ return self.uri == other.uri \
+ and self.regex == other.regex \
+ and self.value == other.value \
+ and self.verb == other.verb \
+ and self.remain == other.remain \
+ and self.unit == other.unit \
+ and self.next_available == other.next_available
+
+ def __repr__(self):
+ return "<RateLimit: method=%s uri=%s>" % (self.method, self.uri)
+
+
+class AbsoluteLimit(object):
+ """Data model that represents a single absolute limit"""
+
+ def __init__(self, name, value):
+ self.name = name
+ self.value = value
+
+ def __eq__(self, other):
+ return self.value == other.value and self.name == other.name
+
+ def __repr__(self):
+ return "<AbsoluteLimit: name=%s>" % (self.name)
+
+
+class LimitsManager(base.Manager):
+ """Manager object used to interact with limits resource"""
+
+ resource_class = Limits
+
+ def get(self):
+ """
+ Get a specific extension.
+
+ :rtype: :class:`Limits`
+ """
+ return self._get("/limits", "limits")
diff --git a/novaclient/v1_1/shell.py b/novaclient/v1_1/shell.py
index 97e576c6..45398b3c 100644
--- a/novaclient/v1_1/shell.py
+++ b/novaclient/v1_1/shell.py
@@ -1207,3 +1207,17 @@ def do_keypair_list(cs, args):
keypairs = cs.keypairs.list()
columns = ['Name', 'Fingerprint']
utils.print_list(keypairs, columns)
+
+
+def do_absolute_limits(cs, args):
+ """Print a list of absolute limits for a user"""
+ limits = cs.limits.get().absolute
+ columns = ['Name', 'Value']
+ utils.print_list(limits, columns)
+
+
+def do_rate_limits(cs, args):
+ """Print a list of rate limits for a user"""
+ limits = cs.limits.get().rate
+ columns = ['Verb', 'URI', 'Value', 'Remain', 'Unit', 'Next_Available']
+ utils.print_list(limits, columns)
diff --git a/setup.py b/setup.py
index d69ad981..4741af5f 100644
--- a/setup.py
+++ b/setup.py
@@ -28,7 +28,7 @@ def read_file(file_name):
setuptools.setup(
name="python-novaclient",
- version="2.6.8",
+ version="2.6.9",
author="Rackspace, based on work by Jacob Kaplan-Moss",
author_email="github@racklabs.com",
description="Client library for OpenStack Nova API.",
diff --git a/tests/v1_1/fakes.py b/tests/v1_1/fakes.py
index ce637908..ccfb6435 100644
--- a/tests/v1_1/fakes.py
+++ b/tests/v1_1/fakes.py
@@ -55,56 +55,55 @@ class FakeHTTPClient(base_client.HTTPClient):
return (200, {"limits": {
"rate": [
{
- "verb": "POST",
- "URI": "*",
+ "uri": "*",
"regex": ".*",
- "value": 10,
- "remaining": 2,
- "unit": "MINUTE",
- "resetTime": 1244425439
+ "limit": [
+ {
+ "value": 10,
+ "verb": "POST",
+ "remaining": 2,
+ "unit": "MINUTE",
+ "next-available": "2011-12-15T22:42:45Z"
+ },
+ {
+ "value": 10,
+ "verb": "PUT",
+ "remaining": 2,
+ "unit": "MINUTE",
+ "next-available": "2011-12-15T22:42:45Z"
+ },
+ {
+ "value": 100,
+ "verb": "DELETE",
+ "remaining": 100,
+ "unit": "MINUTE",
+ "next-available": "2011-12-15T22:42:45Z"
+ }
+ ]
},
{
- "verb": "POST",
- "URI": "*/servers",
+ "uri": "*/servers",
"regex": "^/servers",
- "value": 50,
- "remaining": 49,
- "unit": "DAY", "resetTime": 1244511839
- },
- {
- "verb": "PUT",
- "URI": "*",
- "regex": ".*",
- "value": 10,
- "remaining": 2,
- "unit": "MINUTE",
- "resetTime": 1244425439
- },
- {
- "verb": "GET",
- "URI": "*changes-since*",
- "regex": "changes-since",
- "value": 3,
- "remaining": 3,
- "unit": "MINUTE",
- "resetTime": 1244425439
- },
- {
- "verb": "DELETE",
- "URI": "*",
- "regex": ".*",
- "value": 100,
- "remaining": 100,
- "unit": "MINUTE",
- "resetTime": 1244425439
+ "limit": [
+ {
+ "verb": "POST",
+ "value": 25,
+ "remaining": 24,
+ "unit": "DAY",
+ "next-available": "2011-12-15T22:42:45Z"
+ }
+ ]
}
],
"absolute": {
"maxTotalRAMSize": 51200,
- "maxIPGroups": 50,
- "maxIPGroupMembers": 25
- }
- }})
+ "maxServerMeta": 5,
+ "maxImageMeta": 5,
+ "maxPersonality": 5,
+ "maxPersonalitySize": 10240
+ },
+ },
+ })
#
# Servers
diff --git a/tests/v1_1/test_limits.py b/tests/v1_1/test_limits.py
new file mode 100644
index 00000000..91e6f23e
--- /dev/null
+++ b/tests/v1_1/test_limits.py
@@ -0,0 +1,52 @@
+
+from novaclient.v1_1 import limits
+from tests.v1_1 import fakes
+from tests import utils
+
+
+cs = fakes.FakeClient()
+
+
+class LimitsTest(utils.TestCase):
+
+ def test_get_limits(self):
+ obj = cs.limits.get()
+ cs.assert_called('GET', '/limits')
+ self.assertTrue(isinstance(obj, limits.Limits))
+
+ def test_absolute_limits(self):
+ obj = cs.limits.get()
+
+ expected = (
+ limits.AbsoluteLimit("maxTotalRAMSize", 51200),
+ limits.AbsoluteLimit("maxServerMeta", 5),
+ limits.AbsoluteLimit("maxImageMeta", 5),
+ limits.AbsoluteLimit("maxPersonality", 5),
+ limits.AbsoluteLimit("maxPersonalitySize", 10240),
+ )
+
+ abs_limits = list(obj.absolute)
+ self.assertEqual(len(abs_limits), len(expected))
+
+ for limit in abs_limits:
+ self.assertTrue(limit in expected)
+
+ def test_rate_limits(self):
+ obj = cs.limits.get()
+
+ expected = (
+ limits.RateLimit('POST', '*', '.*', 10, 2, 'MINUTE',
+ '2011-12-15T22:42:45Z' ),
+ limits.RateLimit('PUT', '*', '.*', 10, 2, 'MINUTE',
+ '2011-12-15T22:42:45Z' ),
+ limits.RateLimit('DELETE', '*', '.*', 100, 100, 'MINUTE',
+ '2011-12-15T22:42:45Z' ),
+ limits.RateLimit('POST', '*/servers', '^/servers', 25, 24, 'DAY',
+ '2011-12-15T22:42:45Z' ),
+ )
+
+ rate_limits = list(obj.rate)
+ self.assertEqual(len(rate_limits), len(expected))
+
+ for limit in rate_limits:
+ self.assertTrue(limit in expected)