From 168636e744012f264310897603eb4e3dde6d1df8 Mon Sep 17 00:00:00 2001 From: Haiwei Xu Date: Wed, 26 Dec 2012 11:24:55 +0000 Subject: [PATCH] Check tenant_id's format in "nova quota-update" Fix bug 1088835 "nova quota-update" command is executed without checking the format of the tenant_id argument. The tenant_id should be in the format of UUID. The tenant_id of quotas should be in accord with the form of keystone's tenant_id. So this patch checks the format of the tenant_id when "nova quota-update" command is executed. Change-Id: I47c4f2ff9adbab5da4697270dcf024ac88e24529 --- novaclient/utils.py | 13 +++++++ novaclient/v1_1/shell.py | 4 +++ tests/v1_1/fakes.py | 76 +++++++++++++++++++++++++++++++++++++-- tests/v1_1/test_quotas.py | 6 ++-- tests/v1_1/test_shell.py | 19 +++++++--- 5 files changed, 110 insertions(+), 8 deletions(-) diff --git a/novaclient/utils.py b/novaclient/utils.py index bf76a7316..90902a2e2 100644 --- a/novaclient/utils.py +++ b/novaclient/utils.py @@ -289,3 +289,16 @@ def slugify(value): value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore') value = unicode(_slugify_strip_re.sub('', value).strip().lower()) return _slugify_hyphenate_re.sub('-', value) + + +def is_uuid_like(val): + """ + The UUID which doesn't contain hyphens or 'A-F' is allowed. + """ + try: + if uuid.UUID(val) and val.isalnum() and val.islower(): + return True + else: + return False + except (TypeError, ValueError, AttributeError): + return False diff --git a/novaclient/v1_1/shell.py b/novaclient/v1_1/shell.py index 92b77f883..ff74a3fcc 100644 --- a/novaclient/v1_1/shell.py +++ b/novaclient/v1_1/shell.py @@ -2532,6 +2532,10 @@ def _quota_show(quotas): def _quota_update(manager, identifier, args): updates = {} + if not utils.is_uuid_like(identifier): + raise exceptions.CommandError( + "error: Invalid tenant-id %s supplied for update" + % identifier) for resource in _quota_resources: val = getattr(args, resource, None) if val is not None: diff --git a/tests/v1_1/fakes.py b/tests/v1_1/fakes.py index 36aafca31..48ab33d1a 100644 --- a/tests/v1_1/fakes.py +++ b/tests/v1_1/fakes.py @@ -863,6 +863,57 @@ class FakeHTTPClient(base_client.HTTPClient): 'security_groups': 1, 'security_group_rules': 1}}) + def get_os_quota_sets_97f4c221bff44578b0300df4ef119353(self, **kw): + return (200, {}, {'quota_set': { + 'tenant_id': '97f4c221bff44578b0300df4ef119353', + 'metadata_items': [], + 'injected_file_content_bytes': 1, + 'injected_file_path_bytes': 1, + 'volumes': 1, + 'gigabytes': 1, + 'ram': 1, + 'floating_ips': 1, + 'instances': 1, + 'injected_files': 1, + 'cores': 1, + 'keypairs': 1, + 'security_groups': 1, + 'security_group_rules': 1}}) + + def put_os_quota_sets_97f4c221_bff4_4578_b030_0df4ef119353(self, **kw): + return (200, {}, {'quota_set': { + 'tenant_id': '97f4c221-bff4-4578-b030-0df4ef119353', + 'metadata_items': [], + 'injected_file_content_bytes': 1, + 'injected_file_path_bytes': 1, + 'volumes': 1, + 'gigabytes': 1, + 'ram': 1, + 'floating_ips': 1, + 'instances': 1, + 'injected_files': 1, + 'cores': 1, + 'keypairs': 1, + 'security_groups': 1, + 'security_group_rules': 1}}) + + def get_os_quota_sets_97f4c221_bff4_4578_b030_0df4ef119353(self, **kw): + return (200, {}, {'quota_set': { + 'tenant_id': '97f4c221-bff4-4578-b030-0df4ef119353', + 'metadata_items': [], + 'injected_file_content_bytes': 1, + 'injected_file_path_bytes': 1, + 'volumes': 1, + 'gigabytes': 1, + 'ram': 1, + 'floating_ips': 1, + 'instances': 1, + 'injected_files': 1, + 'cores': 1, + 'keypairs': 1, + 'security_groups': 1, + 'security_group_rules': 1}}) + def get_os_quota_sets_test_defaults(self): return (200, {}, {'quota_set': { 'tenant_id': 'test', @@ -880,12 +931,12 @@ class FakeHTTPClient(base_client.HTTPClient): 'security_groups': 1, 'security_group_rules': 1}}) - def put_os_quota_sets_test(self, body, **kw): + def put_os_quota_sets_97f4c221bff44578b0300df4ef119353(self, body, **kw): assert body.keys() == ['quota_set'] fakes.assert_has_keys(body['quota_set'], required=['tenant_id']) return (200, {}, {'quota_set': { - 'tenant_id': 'test', + 'tenant_id': '97f4c221bff44578b0300df4ef119353', 'metadata_items': [], 'injected_file_content_bytes': 1, 'injected_file_path_bytes': 1, @@ -941,6 +992,27 @@ class FakeHTTPClient(base_client.HTTPClient): 'security_groups': 1, 'security_group_rules': 1}}) + def put_os_quota_class_sets_97f4c221bff44578b0300df4ef119353(self, + body, **kw): + assert body.keys() == ['quota_class_set'] + fakes.assert_has_keys(body['quota_class_set'], + required=['class_name']) + return (200, {}, {'quota_class_set': { + 'class_name': '97f4c221bff44578b0300df4ef119353', + 'metadata_items': [], + 'injected_file_content_bytes': 1, + 'injected_file_path_bytes': 1, + 'volumes': 2, + 'gigabytes': 1, + 'ram': 1, + 'floating_ips': 1, + 'instances': 1, + 'injected_files': 1, + 'cores': 1, + 'keypairs': 1, + 'security_groups': 1, + 'security_group_rules': 1}}) + # # Security Groups # diff --git a/tests/v1_1/test_quotas.py b/tests/v1_1/test_quotas.py index 61e06ef67..27cdb26ee 100644 --- a/tests/v1_1/test_quotas.py +++ b/tests/v1_1/test_quotas.py @@ -16,6 +16,7 @@ from tests import utils from tests.v1_1 import fakes +from novaclient import exceptions cs = fakes.FakeClient() @@ -33,9 +34,10 @@ class QuotaSetsTest(utils.TestCase): cs.assert_called('GET', '/os-quota-sets/%s/defaults' % tenant_id) def test_update_quota(self): - q = cs.quotas.get('test') + q = cs.quotas.get('97f4c221bff44578b0300df4ef119353') q.update(volumes=2) - cs.assert_called('PUT', '/os-quota-sets/test') + cs.assert_called('PUT', + '/os-quota-sets/97f4c221bff44578b0300df4ef119353') def test_refresh_quota(self): q = cs.quotas.get('test') diff --git a/tests/v1_1/test_shell.py b/tests/v1_1/test_shell.py index 8fd88757a..8e206e5ec 100644 --- a/tests/v1_1/test_shell.py +++ b/tests/v1_1/test_shell.py @@ -702,16 +702,27 @@ class ShellTest(utils.TestCase): self.assert_called('GET', '/os-quota-sets/test/defaults') def test_quota_update(self): - self.run_command('quota-update test --instances=5') - self.assert_called('PUT', '/os-quota-sets/test') + self.run_command( + 'quota-update 97f4c221bff44578b0300df4ef119353 \ + --instances=5') + self.assert_called('PUT', + '/os-quota-sets/97f4c221bff44578b0300df4ef119353') + + def test_quota_update_error(self): + self.assertRaises(exceptions.CommandError, + self.run_command, + 'quota-update 7f4c221-bff4-4578-b030-0df4ef119353 \ + --instances=5') def test_quota_class_show(self): self.run_command('quota-class-show test') self.assert_called('GET', '/os-quota-class-sets/test') def test_quota_class_update(self): - self.run_command('quota-class-update test --instances=5') - self.assert_called('PUT', '/os-quota-class-sets/test') + self.run_command('quota-class-update 97f4c221bff44578b0300df4ef119353 \ + --instances=5') + self.assert_called('PUT', + '/os-quota-class-sets/97f4c221bff44578b0300df4ef119353') def test_network_list(self): self.run_command('network-list')