From 49b64b171546eb318619ccbd14a31d5aa562cef7 Mon Sep 17 00:00:00 2001 From: Sachin Bansal Date: Mon, 8 Sep 2014 17:44:26 -0700 Subject: [PATCH] We will now store default quotas in default-project. It will be overwritten every time api server is restarted. Earlier, we were writing configured values in each project which makes us not able to distinguish between the cases where quota values are set on that project or not. As a result, subsequent updates to quota values were not being applied to existing projects. With the new change, we will for each resource, we will first check if it is configured for that project. If not, we will check the default-project (which is configured through the config file), then finally code default value of -1 Change-Id: I36eed73a028b945bf51a4f74a8e9eb625cf4bf20 Closes-Bug: 1363914 (cherry picked from commit 9bb29366cee89797cd1199bbee5ed638586507fc) --- src/config/api-server/vnc_addr_mgmt.py | 2 - src/config/api-server/vnc_cfg_ifmap.py | 20 +++++++ src/config/api-server/vnc_cfg_types.py | 52 +++++++---------- src/config/api-server/vnc_quota.py | 58 +++++-------------- .../vnc_openstack/vnc_openstack/__init__.py | 38 +----------- 5 files changed, 55 insertions(+), 115 deletions(-) diff --git a/src/config/api-server/vnc_addr_mgmt.py b/src/config/api-server/vnc_addr_mgmt.py index 6aa56d8d85d..623f60c9dfd 100644 --- a/src/config/api-server/vnc_addr_mgmt.py +++ b/src/config/api-server/vnc_addr_mgmt.py @@ -543,8 +543,6 @@ def net_check_subnet_quota(self, db_vn_dict, req_vn_dict, db_conn): return (False, 'Internal error : ' + pformat(proj_dict)) obj_type = 'subnet' - QuotaHelper.ensure_quota_project_present(obj_type, proj_uuid, - proj_dict, db_conn) for network in proj_dict.get('virtual_networks', []): if network['uuid'] == db_vn_dict['uuid']: continue diff --git a/src/config/api-server/vnc_cfg_ifmap.py b/src/config/api-server/vnc_cfg_ifmap.py index fff58ecb1bc..53095f26db9 100644 --- a/src/config/api-server/vnc_cfg_ifmap.py +++ b/src/config/api-server/vnc_cfg_ifmap.py @@ -62,6 +62,7 @@ from provision_defaults import * import cfgm_common.imid from cfgm_common.exceptions import * +from vnc_quota import * from gen.vnc_ifmap_client_gen import * from gen.vnc_cassandra_client_gen import * from pysandesh.connection_info import ConnectionState @@ -1413,6 +1414,24 @@ def __init__(self, api_svr_mgr, ifmap_srv_ip, ifmap_srv_port, uname, reset_config, db_prefix) # end __init__ + def _update_default_quota(self): + """ Read the default quotas from the configuration + and update it in the project object if not already + updated. + """ + default_quota = QuotaHelper.default_quota + + proj_id = self.fq_name_to_uuid('project', + ['default-domain', 'default-project']) + (ok, proj_dict) = self.dbe_read('project', {'uuid':proj_id}) + if not ok: + return + quota = QuotaType() + + proj_dict['quota'] = default_quota + self.dbe_update('project', {'uuid':proj_id}, proj_dict) + # end _update_default_quota + def db_resync(self): # Read contents from cassandra and publish to ifmap mapclient = self._ifmap_db._mapclient @@ -1427,6 +1446,7 @@ def db_resync(self): PublishRequest(mapclient.get_session_id(), upd_str)) self._ifmap_db.accumulator = None self._ifmap_db.accumulated_request_len = 0 + self._update_default_quota() end_time = datetime.datetime.utcnow() logger.info("Time elapsed in syncing ifmap: %s" % (str(end_time - start_time))) self._db_resync_done.set() diff --git a/src/config/api-server/vnc_cfg_types.py b/src/config/api-server/vnc_cfg_types.py index 9e680d9b064..deb3354e48d 100644 --- a/src/config/api-server/vnc_cfg_types.py +++ b/src/config/api-server/vnc_cfg_types.py @@ -77,7 +77,6 @@ def http_post_collection(cls, tenant_name, obj_dict, db_conn): return (False, (500, 'Internal error : ' + pformat(proj_dict))) obj_type = 'floating-ip' - QuotaHelper.ensure_quota_project_present(obj_type, proj_uuid, proj_dict, db_conn) if 'floating_ip_back_refs' in proj_dict: quota_count = len(proj_dict['floating_ip_back_refs']) @@ -258,7 +257,6 @@ def http_post_collection(cls, tenant_name, obj_dict, db_conn): return (False, (500, 'Internal error : ' + pformat(proj_dict))) obj_type = 'logical-router' - QuotaHelper.ensure_quota_project_present(obj_type, proj_uuid, proj_dict, db_conn) if 'logical_routers' in proj_dict: quota_count = len(proj_dict['logical_routers']) (ok, quota_limit) = QuotaHelper.check_quota_limit(proj_dict, obj_type, quota_count) @@ -282,23 +280,21 @@ def http_post_collection(cls, tenant_name, obj_dict, db_conn): if not vn_fq_name: return (False, (500, 'Internal error : ' + pformat(vn_dict))) vn_uuid = db_conn.fq_name_to_uuid('virtual-network', vn_fq_name) - (ok, vn_dict) = QuotaHelper.get_objtype_dict(vn_uuid, 'virtual-network', db_conn) + (ok, vn_dict) = db_conn.dbe_read('virtual-network', {'uuid':vn_uuid}) if not ok: return (False, (500, 'Internal error : ' + pformat(vn_dict))) - if vn_dict['parent_type'] == 'project': - proj_uuid = vn_dict['parent_uuid'] - (ok, proj_dict) = QuotaHelper.get_project_dict(proj_uuid, db_conn) - if not ok: - return (False, (500, 'Internal error : ' + pformat(proj_dict))) + proj_uuid = vn_dict['parent_uuid'] + (ok, proj_dict) = QuotaHelper.get_project_dict(proj_uuid, db_conn) + if not ok: + return (False, (500, 'Internal error : ' + pformat(proj_dict))) - obj_type = 'virtual-machine-interface' - QuotaHelper.ensure_quota_project_present(obj_type, proj_uuid, proj_dict, db_conn) - if 'virtual_machine_interfaces' in proj_dict: - quota_count = len(proj_dict['virtual_machine_interfaces']) - (ok, quota_limit) = QuotaHelper.check_quota_limit(proj_dict, obj_type, quota_count) - if not ok: - return (False, (403, pformat(obj_dict['fq_name']) + ' : ' + quota_limit)) + obj_type = 'virtual-machine-interface' + if 'virtual_machine_interfaces' in proj_dict: + quota_count = len(proj_dict['virtual_machine_interfaces']) + (ok, quota_limit) = QuotaHelper.check_quota_limit(proj_dict, obj_type, quota_count) + if not ok: + return (False, (403, pformat(obj_dict['fq_name']) + ' : ' + quota_limit)) inmac = None if 'virtual_machine_interface_mac_addresses' in obj_dict: @@ -360,7 +356,6 @@ def http_post_collection(cls, tenant_name, obj_dict, db_conn): return (False, (500, 'Internal error : ' + pformat(proj_dict))) obj_type = 'virtual-network' - QuotaHelper.ensure_quota_project_present(obj_type, proj_uuid, proj_dict, db_conn) if 'virtual_networks' in proj_dict: quota_count = len(proj_dict['virtual_networks']) (ok, quota_limit) = QuotaHelper.check_quota_limit(proj_dict, obj_type, quota_count) @@ -824,7 +819,6 @@ def http_post_collection(cls, tenant_name, obj_dict, db_conn): return (False, (500, 'Internal error : ' + pformat(proj_dict))) obj_type = 'security-group' - QuotaHelper.ensure_quota_project_present(obj_type, proj_uuid, proj_dict, db_conn) if 'security_groups' in proj_dict: quota_count = len(proj_dict['security_groups']) (ok, quota_limit) = QuotaHelper.check_quota_limit(proj_dict, obj_type, quota_count) @@ -838,22 +832,19 @@ def http_post_collection(cls, tenant_name, obj_dict, db_conn): @classmethod def http_put(cls, id, fq_name, obj_dict, db_conn): - (ok, sec_dict) = QuotaHelper.get_objtype_dict(obj_dict['uuid'], 'security-group', db_conn) + (ok, sec_dict) = db_conn.dbe_read('security-group', {'uuid': id}) + if not ok: + return (False, (500, 'Bad Security Group error : ' + pformat(sec_dict))) + (ok, proj_dict) = QuotaHelper.get_project_dict(sec_dict['parent_uuid'], db_conn) if not ok: - return (False, (500, 'Bad Security Group error : ' + pformat(proj_dict))) + return (False, (500, 'Bad Project error : ' + pformat(proj_dict))) - if sec_dict['parent_type'] == 'project': - (ok, proj_dict) = QuotaHelper.get_project_dict(sec_dict['parent_uuid'], db_conn) + obj_type = 'security-group-rule' + if 'security_group_entries' in obj_dict: + quota_count = len(obj_dict['security_group_entries']['policy_rule']) + (ok, quota_limit) = QuotaHelper.check_quota_limit(proj_dict, obj_type, quota_count) if not ok: - return (False, (500, 'Bad Project error : ' + pformat(proj_dict))) - - obj_type = 'security-group-rule' - QuotaHelper.ensure_quota_project_present(obj_type, proj_dict['uuid'], proj_dict, db_conn) - if 'security_group_entries' in obj_dict: - quota_count = len(obj_dict['security_group_entries']['policy_rule']) - (ok, quota_limit) = QuotaHelper.check_quota_limit(proj_dict, obj_type, quota_count) - if not ok: - return (False, (403, pformat(fq_name) + ' : ' + quota_limit)) + return (False, (403, pformat(fq_name) + ' : ' + quota_limit)) _check_policy_rule_uuid(obj_dict.get('security_group_entries')) return True, "" @@ -877,7 +868,6 @@ def http_post_collection(cls, tenant_name, obj_dict, db_conn): return (False, (500, 'Internal error : ' + pformat(proj_dict))) obj_type = 'network-policy' - QuotaHelper.ensure_quota_project_present(obj_type, proj_uuid, proj_dict, db_conn) if 'network-policys' in proj_dict: quota_count = len(proj_dict['network-policys']) (ok, quota_limit) = QuotaHelper.check_quota_limit(proj_dict, obj_type, quota_count) diff --git a/src/config/api-server/vnc_quota.py b/src/config/api-server/vnc_quota.py index 1cd5edb5906..f0f3553664d 100644 --- a/src/config/api-server/vnc_quota.py +++ b/src/config/api-server/vnc_quota.py @@ -6,57 +6,25 @@ class QuotaHelper(object): default_quota = { - 'default': -1 + 'defaults': -1 } - @staticmethod - def ensure_quota_project_present(obj_type, proj_uuid, proj_dict, db_conn): - quota = QuotaType() - if 'quota' in proj_dict.keys(): - quota = QuotaType(**proj_dict['quota']) - quota.set_defaults(QuotaHelper.default_quota['default']) - - set_quota_method = 'set_' + obj_type.replace('-','_') - get_quota_method = 'get_' + obj_type.replace('-','_') - if hasattr(quota, set_quota_method): - get_quota = getattr(quota, get_quota_method) - if get_quota() == None: - set_quota = getattr(quota, set_quota_method) - if obj_type in QuotaHelper.default_quota.keys(): - set_quota(QuotaHelper.default_quota[obj_type]) - else: - set_quota(quota.get_defaults()) - - proj_dict['quota'] = quota.__dict__ - (ok, result) = db_conn.dbe_update('project', {'uuid': proj_dict['uuid']}, proj_dict) - if not ok: - return (False, 'Cannot update project object') - return (True, proj_dict) - - @staticmethod - def get_objtype_dict(proj_uuid, obj_type, db_conn): - proj_id = {'uuid': proj_uuid} - (ok, proj_dict) = db_conn.dbe_read(obj_type, proj_id) - if not ok: - return (False, obj_type + ' is not valid') + @classmethod + def get_project_dict(cls, proj_uuid, db_conn): + (ok, proj_dict) = db_conn.dbe_read('project', {'uuid': proj_uuid}) return (ok, proj_dict) - @staticmethod - def get_project_dict(proj_uuid, db_conn): - return QuotaHelper.get_objtype_dict(proj_uuid, 'project', db_conn) - - @staticmethod - def get_quota_limit(proj_dict, obj_type): - quota = proj_dict['quota'] + @classmethod + def get_quota_limit(cls, proj_dict, obj_type): + quota = proj_dict.get('quota') or cls.default_quota quota_type = obj_type.replace('-','_') - if proj_dict['quota'].get(quota_type) is not None: - return proj_dict['quota'][quota_type] - return QuotaHelper.default_quota['default'] + return (quota.get(quota_type) or + cls.default_quota.get(quota_type) or + cls.default_quota['defaults']) - @staticmethod - def check_quota_limit(proj_dict, obj_type, quota_count): - quota_limit = QuotaHelper.get_quota_limit(proj_dict, obj_type) + @classmethod + def check_quota_limit(cls, proj_dict, obj_type, quota_count): + quota_limit = cls.get_quota_limit(proj_dict, obj_type) if quota_limit > 0 and quota_count >= quota_limit: return (False, 'quota limit (%d) exceeded for resource %s' % (quota_limit, obj_type)) return (True, quota_limit) - diff --git a/src/config/vnc_openstack/vnc_openstack/__init__.py b/src/config/vnc_openstack/vnc_openstack/__init__.py index 48674265b0d..71674e69252 100644 --- a/src/config/vnc_openstack/vnc_openstack/__init__.py +++ b/src/config/vnc_openstack/vnc_openstack/__init__.py @@ -15,6 +15,7 @@ import Queue import ConfigParser import keystoneclient.v2_0.client as keystone + import cfgm_common try: from cfgm_common import vnc_plugin_base @@ -636,41 +637,6 @@ def _create_default_security_group(self, proj_dict): self._vnc_lib.security_group_create(sg_obj) # end _create_default_security_group - def _update_default_quota(self, id): - """ Read the default quotas from the configuration - and update it in the project object if not already - updated. - """ - if 'QUOTA' not in self._config_sections.sections(): - return - default_quota = {} - for (k, v) in self._config_sections.items("QUOTA"): - try: - key = str(k).replace('-', '_') - default_quota[key] = int(v) - except ValueError: - pass - - # calling vnc_lib.project_read leads to a recursive call - # to the function pre_project_read. But since the project id is - # added to the _vnc_projects list before calling this function, - # there will not be any infinite recursive calls. - proj_obj = self._vnc_lib.project_read(id=id) - quota = proj_obj.get_quota() - modified = False - for k in default_quota.keys(): - get_quota = getattr(quota, 'get_' + k) - set_quota = getattr(quota, 'set_' + k) - if get_quota is None or set_quota is None: - continue - if get_quota() is None or get_quota() == -1: - modified = True - set_quota(default_quota[k]) - - if modified: - proj_obj.set_quota(quota) - self._vnc_lib.project_update(proj_obj) - def pre_domain_read(self, id): if not self._keystone_sync_on_demand: # domain added via poll @@ -702,8 +668,6 @@ def pre_project_read(self, id): pass self._vnc_projects.add(id) - # update default quota from the configuration file - self._update_default_quota(id) # end pre_project_read def post_project_create(self, proj_dict):