Skip to content

Commit

Permalink
We will now store default quotas in default-project.
Browse files Browse the repository at this point in the history
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 9bb2936)
  • Loading branch information
Sachin Bansal committed Oct 1, 2014
1 parent 26ca018 commit 49b64b1
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 115 deletions.
2 changes: 0 additions & 2 deletions src/config/api-server/vnc_addr_mgmt.py
Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions src/config/api-server/vnc_cfg_ifmap.py
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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()
Expand Down
52 changes: 21 additions & 31 deletions src/config/api-server/vnc_cfg_types.py
Expand Up @@ -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'])
Expand Down Expand Up @@ -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)
Expand All @@ -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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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, ""
Expand All @@ -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)
Expand Down
58 changes: 13 additions & 45 deletions src/config/api-server/vnc_quota.py
Expand Up @@ -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)

38 changes: 1 addition & 37 deletions src/config/vnc_openstack/vnc_openstack/__init__.py
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down

0 comments on commit 49b64b1

Please sign in to comment.