diff --git a/reddwarfclient/cli.py b/reddwarfclient/cli.py index d3e65af3..2daa5aa5 100644 --- a/reddwarfclient/cli.py +++ b/reddwarfclient/cli.py @@ -228,10 +228,19 @@ class VersionCommands(common.AuthedCommandsBase): self._pretty_list(self.dbaas.versions.index, self.url) +class LimitsCommands(common.AuthedCommandsBase): + """Show the rate limits and absolute limits""" + + def list(self): + """List the rate limits and absolute limits""" + self._pretty_list(self.dbaas.limits.index) + + COMMANDS = {'auth': common.Auth, 'instance': InstanceCommands, 'flavor': FlavorsCommands, 'database': DatabaseCommands, + 'limit': LimitsCommands, 'user': UserCommands, 'root': RootCommands, 'version': VersionCommands, diff --git a/reddwarfclient/client.py b/reddwarfclient/client.py index 0fde5dee..64c4db21 100644 --- a/reddwarfclient/client.py +++ b/reddwarfclient/client.py @@ -301,6 +301,7 @@ class Dbaas(object): from reddwarfclient.databases import Databases from reddwarfclient.flavors import Flavors from reddwarfclient.instances import Instances + from reddwarfclient.limits import Limits from reddwarfclient.users import Users from reddwarfclient.root import Root from reddwarfclient.hosts import Hosts @@ -322,6 +323,7 @@ class Dbaas(object): self.databases = Databases(self) self.flavors = Flavors(self) self.instances = Instances(self) + self.limits = Limits(self) self.users = Users(self) self.root = Root(self) self.hosts = Hosts(self) diff --git a/reddwarfclient/limits.py b/reddwarfclient/limits.py new file mode 100644 index 00000000..61793128 --- /dev/null +++ b/reddwarfclient/limits.py @@ -0,0 +1,41 @@ +# Copyright (c) 2013 OpenStack, LLC. +# All Rights Reserved. +# +# 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 reddwarfclient import base +import exceptions + + +class Limits(base.ManagerWithFind): + """ + Manages :class `Limit` resources + """ + resource_class = base.Resource + + def index(self): + """ + Retrieve the limits + """ + RESPONSE_KEY = "limits" + URL = "/limits" + resp, body = self.api.client.get(URL) + + if resp is None or resp.status != 200: + raise exceptions.from_response(resp, body) + + if not body: + raise Exception("Call to " + URL + " did not return a body.") + + rates = body[RESPONSE_KEY]['rate'][0]['limit'] + return [self.resource_class(self, res) for res in rates] diff --git a/tests/test_limits.py b/tests/test_limits.py new file mode 100644 index 00000000..d1e55cd5 --- /dev/null +++ b/tests/test_limits.py @@ -0,0 +1,81 @@ +from testtools import TestCase +from mock import Mock +from reddwarfclient import limits + +""" +This class tests the calling code for the Limits API +""" + + +class LimitsTest(TestCase): + + def setUp(self): + super(LimitsTest, self).setUp() + self.limits = limits.Limits(Mock()) + self.limits.api.client = Mock() + + def tearDown(self): + super(LimitsTest, self).tearDown() + + def test_index(self): + RESPONSE_KEY = "limits" + + resp = Mock() + resp.status = 200 + body = {RESPONSE_KEY: {'rate': [ + {'limit': [ + { + "next-available": "2013-02-26T00:00:13Z", + "remaining": 100, + "unit": "MINUTE", + "value": 100, + "verb": "POST" + }, + { + "next-available": "2013-02-26T00:00:13Z", + "remaining": 100, + "unit": "MINUTE", + "value": 100, + "verb": "PUT" + }, + { + "next-available": "2013-02-26T00:00:13Z", + "remaining": 100, + "unit": "MINUTE", + "value": 100, + "verb": "DELETE" + }, + { + "next-available": "2013-02-26T00:00:13Z", + "remaining": 99, + "unit": "MINUTE", + "value": 100, + "verb": "GET" + } + ] + }]}} + response = (resp, body) + + mock_get = Mock(return_value=response) + self.limits.api.client.get = mock_get + self.assertIsNotNone(self.limits.index()) + mock_get.assert_called_once_with("/limits") + + def test_index_errors(self): + status_list = [400, 401, 403, 404, 408, 409, 413, 500, 501] + for status_code in status_list: + self._check_error_response(status_code) + + def _check_error_response(self, status_code): + RESPONSE_KEY = "limits" + + resp = Mock() + resp.status = status_code + body = {RESPONSE_KEY: {'rate': [ + {'limit': [] + }]}} + response = (resp, body) + + mock_get = Mock(return_value=response) + self.limits.api.client.get = mock_get + self.assertRaises(Exception, self.limits.index)