summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Yeoh <cyeoh@au1.ibm.com>2013-12-11 17:49:25 +1030
committerChris Yeoh <cyeoh@au1.ibm.com>2013-12-19 23:36:00 +1030
commitcfd38a7ef67c1495128a495a6cd832ca63e65a24 (patch)
tree2e6568550549f1fd57d6634e758e048f3447ecc7
parent40a1c128283f64ed7d30f37004112429bc1f0628 (diff)
Adds first part of quotas support for Nova V3 API
Adds support and tests for the os-quotas extension for the Nova V3 API. Note that compared to the V2 version this removes the ability to set quotas which are not relevant to the V3 API (eg injected file quotas are not relevant because the os-personalities extension has been removed) Partially implements blueprint v3-api Change-Id: Ifa1c77428424bedf7fb88ef6d7b3843376799d24
Notes
Notes (review): Verified+2: Jenkins Code-Review+2: Kevin L. Mitchell <kevin.mitchell@rackspace.com> Code-Review+1: garyk <gkotton@vmware.com> Approved+1: Sean Dague <sean@dague.net> Code-Review+2: Sean Dague <sean@dague.net> Submitted-by: Jenkins Submitted-at: Fri, 20 Dec 2013 14:37:21 +0000 Reviewed-on: https://review.openstack.org/61330 Project: openstack/python-novaclient Branch: refs/heads/master
-rw-r--r--novaclient/tests/v1_1/test_quotas.py44
-rw-r--r--novaclient/tests/v3/fakes.py21
-rw-r--r--novaclient/tests/v3/test_quotas.py33
-rw-r--r--novaclient/v1_1/quotas.py31
-rw-r--r--novaclient/v3/client.py2
-rw-r--r--novaclient/v3/quotas.py27
-rw-r--r--novaclient/v3/shell.py51
7 files changed, 116 insertions, 93 deletions
diff --git a/novaclient/tests/v1_1/test_quotas.py b/novaclient/tests/v1_1/test_quotas.py
index b545e6b..1c67938 100644
--- a/novaclient/tests/v1_1/test_quotas.py
+++ b/novaclient/tests/v1_1/test_quotas.py
@@ -16,54 +16,58 @@
16from novaclient.tests import utils 16from novaclient.tests import utils
17from novaclient.tests.v1_1 import fakes 17from novaclient.tests.v1_1 import fakes
18 18
19cs = fakes.FakeClient()
20
21 19
22class QuotaSetsTest(utils.TestCase): 20class QuotaSetsTest(utils.TestCase):
21 def setUp(self):
22 super(QuotaSetsTest, self).setUp()
23 self.cs = self._get_fake_client()
24
25 def _get_fake_client(self):
26 return fakes.FakeClient()
23 27
24 def test_tenant_quotas_get(self): 28 def test_tenant_quotas_get(self):
25 tenant_id = 'test' 29 tenant_id = 'test'
26 cs.quotas.get(tenant_id) 30 self.cs.quotas.get(tenant_id)
27 cs.assert_called('GET', '/os-quota-sets/%s' % tenant_id) 31 self.cs.assert_called('GET', '/os-quota-sets/%s' % tenant_id)
28 32
29 def test_user_quotas_get(self): 33 def test_user_quotas_get(self):
30 tenant_id = 'test' 34 tenant_id = 'test'
31 user_id = 'fake_user' 35 user_id = 'fake_user'
32 cs.quotas.get(tenant_id, user_id=user_id) 36 self.cs.quotas.get(tenant_id, user_id=user_id)
33 url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id) 37 url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id)
34 cs.assert_called('GET', url) 38 self.cs.assert_called('GET', url)
35 39
36 def test_tenant_quotas_defaults(self): 40 def test_tenant_quotas_defaults(self):
37 tenant_id = '97f4c221bff44578b0300df4ef119353' 41 tenant_id = '97f4c221bff44578b0300df4ef119353'
38 cs.quotas.defaults(tenant_id) 42 self.cs.quotas.defaults(tenant_id)
39 cs.assert_called('GET', '/os-quota-sets/%s/defaults' % tenant_id) 43 self.cs.assert_called('GET', '/os-quota-sets/%s/defaults' % tenant_id)
40 44
41 def test_update_quota(self): 45 def test_update_quota(self):
42 q = cs.quotas.get('97f4c221bff44578b0300df4ef119353') 46 q = self.cs.quotas.get('97f4c221bff44578b0300df4ef119353')
43 q.update(volumes=2) 47 q.update(volumes=2)
44 cs.assert_called('PUT', 48 self.cs.assert_called('PUT',
45 '/os-quota-sets/97f4c221bff44578b0300df4ef119353') 49 '/os-quota-sets/97f4c221bff44578b0300df4ef119353')
46 50
47 def test_update_user_quota(self): 51 def test_update_user_quota(self):
48 tenant_id = '97f4c221bff44578b0300df4ef119353' 52 tenant_id = '97f4c221bff44578b0300df4ef119353'
49 user_id = 'fake_user' 53 user_id = 'fake_user'
50 q = cs.quotas.get(tenant_id) 54 q = self.cs.quotas.get(tenant_id)
51 q.update(volumes=2, user_id=user_id) 55 q.update(volumes=2, user_id=user_id)
52 url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id) 56 url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id)
53 cs.assert_called('PUT', url) 57 self.cs.assert_called('PUT', url)
54 58
55 def test_force_update_quota(self): 59 def test_force_update_quota(self):
56 q = cs.quotas.get('97f4c221bff44578b0300df4ef119353') 60 q = self.cs.quotas.get('97f4c221bff44578b0300df4ef119353')
57 q.update(cores=2, force=True) 61 q.update(cores=2, force=True)
58 cs.assert_called( 62 self.cs.assert_called(
59 'PUT', '/os-quota-sets/97f4c221bff44578b0300df4ef119353', 63 'PUT', '/os-quota-sets/97f4c221bff44578b0300df4ef119353',
60 {'quota_set': {'force': True, 64 {'quota_set': {'force': True,
61 'cores': 2, 65 'cores': 2,
62 'tenant_id': '97f4c221bff44578b0300df4ef119353'}}) 66 'tenant_id': '97f4c221bff44578b0300df4ef119353'}})
63 67
64 def test_refresh_quota(self): 68 def test_refresh_quota(self):
65 q = cs.quotas.get('test') 69 q = self.cs.quotas.get('test')
66 q2 = cs.quotas.get('test') 70 q2 = self.cs.quotas.get('test')
67 self.assertEqual(q.volumes, q2.volumes) 71 self.assertEqual(q.volumes, q2.volumes)
68 q2.volumes = 0 72 q2.volumes = 0
69 self.assertNotEqual(q.volumes, q2.volumes) 73 self.assertNotEqual(q.volumes, q2.volumes)
@@ -72,12 +76,12 @@ class QuotaSetsTest(utils.TestCase):
72 76
73 def test_quotas_delete(self): 77 def test_quotas_delete(self):
74 tenant_id = 'test' 78 tenant_id = 'test'
75 cs.quotas.delete(tenant_id) 79 self.cs.quotas.delete(tenant_id)
76 cs.assert_called('DELETE', '/os-quota-sets/%s' % tenant_id) 80 self.cs.assert_called('DELETE', '/os-quota-sets/%s' % tenant_id)
77 81
78 def test_user_quotas_delete(self): 82 def test_user_quotas_delete(self):
79 tenant_id = 'test' 83 tenant_id = 'test'
80 user_id = 'fake_user' 84 user_id = 'fake_user'
81 cs.quotas.delete(tenant_id, user_id=user_id) 85 self.cs.quotas.delete(tenant_id, user_id=user_id)
82 url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id) 86 url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id)
83 cs.assert_called('DELETE', url) 87 self.cs.assert_called('DELETE', url)
diff --git a/novaclient/tests/v3/fakes.py b/novaclient/tests/v3/fakes.py
index e1f5dbb..f856ce4 100644
--- a/novaclient/tests/v3/fakes.py
+++ b/novaclient/tests/v3/fakes.py
@@ -271,3 +271,24 @@ class FakeHTTPClient(fakes_v1_1.FakeHTTPClient):
271 {"zone_name": "zone-2", 271 {"zone_name": "zone-2",
272 "zone_state": {"available": False}, 272 "zone_state": {"available": False},
273 "hosts": None}]}) 273 "hosts": None}]})
274
275 #
276 # Quotas
277 #
278 def put_os_quota_sets_97f4c221bff44578b0300df4ef119353(self, body, **kw):
279 assert list(body) == ['quota_set']
280 return (200, {}, {'quota_set': {
281 'tenant_id': '97f4c221bff44578b0300df4ef119353',
282 'metadata_items': [],
283 'injected_file_content_bytes': 1,
284 'injected_file_path_bytes': 1,
285 'volumes': 2,
286 'gigabytes': 1,
287 'ram': 1,
288 'floating_ips': 1,
289 'instances': 1,
290 'injected_files': 1,
291 'cores': 1,
292 'keypairs': 1,
293 'security_groups': 1,
294 'security_group_rules': 1}})
diff --git a/novaclient/tests/v3/test_quotas.py b/novaclient/tests/v3/test_quotas.py
new file mode 100644
index 0000000..0f361a4
--- /dev/null
+++ b/novaclient/tests/v3/test_quotas.py
@@ -0,0 +1,33 @@
1# Copyright IBM Corp. 2013
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15from novaclient.tests.v1_1 import test_quotas
16from novaclient.tests.v3 import fakes
17
18
19class QuotaSetsTest(test_quotas.QuotaSetsTest):
20 def setUp(self):
21 super(QuotaSetsTest, self).setUp()
22 self.cs = self._get_fake_client()
23
24 def _get_fake_client(self):
25 return fakes.FakeClient()
26
27 def test_force_update_quota(self):
28 q = self.cs.quotas.get('97f4c221bff44578b0300df4ef119353')
29 q.update(cores=2, force=True)
30 self.cs.assert_called(
31 'PUT', '/os-quota-sets/97f4c221bff44578b0300df4ef119353',
32 {'quota_set': {'force': True,
33 'cores': 2}})
diff --git a/novaclient/v1_1/quotas.py b/novaclient/v1_1/quotas.py
index 601bceb..cd16042 100644
--- a/novaclient/v1_1/quotas.py
+++ b/novaclient/v1_1/quotas.py
@@ -41,31 +41,14 @@ class QuotaSetManager(base.Manager):
41 url = '/os-quota-sets/%s' % tenant_id 41 url = '/os-quota-sets/%s' % tenant_id
42 return self._get(url, "quota_set") 42 return self._get(url, "quota_set")
43 43
44 def update(self, tenant_id, metadata_items=None, 44 def _update_body(self, tenant_id, **kwargs):
45 injected_file_content_bytes=None, injected_file_path_bytes=None, 45 kwargs['tenant_id'] = tenant_id
46 volumes=None, gigabytes=None, 46 return {'quota_set': kwargs}
47 ram=None, floating_ips=None, fixed_ips=None, instances=None,
48 injected_files=None, cores=None, key_pairs=None,
49 security_groups=None, security_group_rules=None, force=None,
50 user_id=None):
51 47
52 body = {'quota_set': { 48 def update(self, tenant_id, **kwargs):
53 'tenant_id': tenant_id, 49
54 'metadata_items': metadata_items, 50 user_id = kwargs.pop('user_id', None)
55 'key_pairs': key_pairs, 51 body = self._update_body(tenant_id, **kwargs)
56 'injected_file_content_bytes': injected_file_content_bytes,
57 'injected_file_path_bytes': injected_file_path_bytes,
58 'volumes': volumes,
59 'gigabytes': gigabytes,
60 'ram': ram,
61 'floating_ips': floating_ips,
62 'fixed_ips': fixed_ips,
63 'instances': instances,
64 'injected_files': injected_files,
65 'cores': cores,
66 'security_groups': security_groups,
67 'security_group_rules': security_group_rules,
68 'force': force}}
69 52
70 for key in list(body['quota_set']): 53 for key in list(body['quota_set']):
71 if body['quota_set'][key] is None: 54 if body['quota_set'][key] is None:
diff --git a/novaclient/v3/client.py b/novaclient/v3/client.py
index 8bfb2bb..f20a8a1 100644
--- a/novaclient/v3/client.py
+++ b/novaclient/v3/client.py
@@ -21,6 +21,7 @@ from novaclient.v3 import flavor_access
21from novaclient.v3 import flavors 21from novaclient.v3 import flavors
22from novaclient.v3 import hosts 22from novaclient.v3 import hosts
23from novaclient.v3 import images 23from novaclient.v3 import images
24from novaclient.v3 import quotas
24from novaclient.v3 import servers 25from novaclient.v3 import servers
25 26
26 27
@@ -63,6 +64,7 @@ class Client(object):
63 self.flavors = flavors.FlavorManager(self) 64 self.flavors = flavors.FlavorManager(self)
64 self.flavor_access = flavor_access.FlavorAccessManager(self) 65 self.flavor_access = flavor_access.FlavorAccessManager(self)
65 self.images = images.ImageManager(self) 66 self.images = images.ImageManager(self)
67 self.quotas = quotas.QuotaSetManager(self)
66 self.servers = servers.ServerManager(self) 68 self.servers = servers.ServerManager(self)
67 69
68 # Add in any extensions... 70 # Add in any extensions...
diff --git a/novaclient/v3/quotas.py b/novaclient/v3/quotas.py
new file mode 100644
index 0000000..19723fa
--- /dev/null
+++ b/novaclient/v3/quotas.py
@@ -0,0 +1,27 @@
1# Copyright 2011 OpenStack Foundation
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16from novaclient.v1_1 import quotas
17
18
19class QuotaSet(quotas.QuotaSet):
20 pass
21
22
23class QuotaSetManager(quotas.QuotaSetManager):
24 resource_class = QuotaSet
25
26 def _update_body(self, tenant_id, **kwargs):
27 return {'quota_set': kwargs}
diff --git a/novaclient/v3/shell.py b/novaclient/v3/shell.py
index 8638224..bca8110 100644
--- a/novaclient/v3/shell.py
+++ b/novaclient/v3/shell.py
@@ -32,7 +32,6 @@ from novaclient.openstack.common import strutils
32from novaclient.openstack.common import timeutils 32from novaclient.openstack.common import timeutils
33from novaclient.openstack.common import uuidutils 33from novaclient.openstack.common import uuidutils
34from novaclient import utils 34from novaclient import utils
35from novaclient.v1_1 import quotas
36from novaclient.v3 import availability_zones 35from novaclient.v3 import availability_zones
37from novaclient.v3 import servers 36from novaclient.v3 import servers
38 37
@@ -2829,10 +2828,7 @@ def do_ssh(cs, args):
2829 2828
2830 2829
2831_quota_resources = ['instances', 'cores', 'ram', 'volumes', 'gigabytes', 2830_quota_resources = ['instances', 'cores', 'ram', 'volumes', 'gigabytes',
2832 'floating_ips', 'fixed_ips', 'metadata_items', 2831 'fixed_ips', 'metadata_items', 'key_pairs']
2833 'injected_files', 'key_pairs',
2834 'injected_file_content_bytes', 'injected_file_path_bytes',
2835 'security_groups', 'security_group_rules']
2836 2832
2837 2833
2838def _quota_show(quotas): 2834def _quota_show(quotas):
@@ -2855,11 +2851,7 @@ def _quota_update(manager, identifier, args):
2855 if updates: 2851 if updates:
2856 # default value of force is None to make sure this client 2852 # default value of force is None to make sure this client
2857 # will be compatibile with old nova server 2853 # will be compatibile with old nova server
2858 force_update = getattr(args, 'force', None) 2854 manager.update(identifier, **updates)
2859 if isinstance(manager, quotas.QuotaSetManager):
2860 manager.update(identifier, force=force_update, **updates)
2861 else:
2862 manager.update(identifier, **updates)
2863 2855
2864 2856
2865@utils.arg('--tenant', 2857@utils.arg('--tenant',
@@ -2911,14 +2903,6 @@ def do_quota_defaults(cs, args):
2911 metavar='<gigabytes>', 2903 metavar='<gigabytes>',
2912 type=int, default=None, 2904 type=int, default=None,
2913 help='New value for the "gigabytes" quota.') 2905 help='New value for the "gigabytes" quota.')
2914@utils.arg('--floating-ips',
2915 metavar='<floating-ips>',
2916 type=int,
2917 default=None,
2918 help='New value for the "floating-ips" quota.')
2919@utils.arg('--floating_ips',
2920 type=int,
2921 help=argparse.SUPPRESS)
2922@utils.arg('--fixed-ips', 2906@utils.arg('--fixed-ips',
2923 metavar='<fixed-ips>', 2907 metavar='<fixed-ips>',
2924 type=int, 2908 type=int,
@@ -2932,42 +2916,11 @@ def do_quota_defaults(cs, args):
2932@utils.arg('--metadata_items', 2916@utils.arg('--metadata_items',
2933 type=int, 2917 type=int,
2934 help=argparse.SUPPRESS) 2918 help=argparse.SUPPRESS)
2935@utils.arg('--injected-files',
2936 metavar='<injected-files>',
2937 type=int,
2938 default=None,
2939 help='New value for the "injected-files" quota.')
2940@utils.arg('--injected_files',
2941 type=int,
2942 help=argparse.SUPPRESS)
2943@utils.arg('--injected-file-content-bytes',
2944 metavar='<injected-file-content-bytes>',
2945 type=int,
2946 default=None,
2947 help='New value for the "injected-file-content-bytes" quota.')
2948@utils.arg('--injected_file_content_bytes',
2949 type=int,
2950 help=argparse.SUPPRESS)
2951@utils.arg('--injected-file-path-bytes',
2952 metavar='<injected-file-path-bytes>',
2953 type=int,
2954 default=None,
2955 help='New value for the "injected-file-path-bytes" quota.')
2956@utils.arg('--key-pairs', 2919@utils.arg('--key-pairs',
2957 metavar='<key-pairs>', 2920 metavar='<key-pairs>',
2958 type=int, 2921 type=int,
2959 default=None, 2922 default=None,
2960 help='New value for the "key-pairs" quota.') 2923 help='New value for the "key-pairs" quota.')
2961@utils.arg('--security-groups',
2962 metavar='<security-groups>',
2963 type=int,
2964 default=None,
2965 help='New value for the "security-groups" quota.')
2966@utils.arg('--security-group-rules',
2967 metavar='<security-group-rules>',
2968 type=int,
2969 default=None,
2970 help='New value for the "security-group-rules" quota.')
2971@utils.arg('--force', 2924@utils.arg('--force',
2972 dest='force', 2925 dest='force',
2973 action="store_true", 2926 action="store_true",