schema_edit = user_edit_schema
multiproject = False
- def __init__(self, db, fs, msg):
- BaseTopic.__init__(self, db, fs, msg)
+ def __init__(self, db, fs, msg, auth):
+ BaseTopic.__init__(self, db, fs, msg, auth)
@staticmethod
def _get_project_filter(session):
schema_edit = project_edit_schema
multiproject = False
- def __init__(self, db, fs, msg):
- BaseTopic.__init__(self, db, fs, msg)
+ def __init__(self, db, fs, msg, auth):
+ BaseTopic.__init__(self, db, fs, msg, auth)
@staticmethod
def _get_project_filter(session):
schema_edit = user_edit_schema
def __init__(self, db, fs, msg, auth):
- UserTopic.__init__(self, db, fs, msg)
- self.auth = auth
+ UserTopic.__init__(self, db, fs, msg, auth)
+ # self.auth = auth
def check_conflict_on_new(self, session, indata):
"""
schema_edit = project_edit_schema
def __init__(self, db, fs, msg, auth):
- ProjectTopic.__init__(self, db, fs, msg)
- self.auth = auth
+ ProjectTopic.__init__(self, db, fs, msg, auth)
+ # self.auth = auth
def check_conflict_on_new(self, session, indata):
"""
raise EngineException("You cannot rename project 'admin'", http_code=HTTPStatus.CONFLICT)
# Check that project name is not used, regardless keystone already checks this
- if self.auth.get_project_list(filter_q={"name": project_name}):
+ if project_name and self.auth.get_project_list(filter_q={"name": project_name}):
raise EngineException("project '{}' is already used".format(project_name), HTTPStatus.CONFLICT)
def check_conflict_on_del(self, session, _id, db_content):
self.check_conflict_on_edit(session, content, indata, _id=_id)
self.format_on_edit(content, indata)
- if "name" in indata:
- content["name"] = indata["name"]
+ deep_update_rfc7396(content, indata)
self.auth.update_project(content["_id"], content)
except ValidationError as e:
raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
multiproject = False
def __init__(self, db, fs, msg, auth, ops):
- BaseTopic.__init__(self, db, fs, msg)
- self.auth = auth
+ BaseTopic.__init__(self, db, fs, msg, auth)
+ # self.auth = auth
self.operations = ops
# self.topic = "roles_operations" if isinstance(auth, AuthconnKeystone) else "roles"
projects = [{
"name": project.name,
"_id": project.id,
- "_admin": project.to_dict().get("_admin", {}) # TODO: REVISE
+ "_admin": project.to_dict().get("_admin", {}), # TODO: REVISE
+ "quotas": project.to_dict().get("quotas", {}), # TODO: REVISE
} for project in projects]
if filter_q and filter_q.get("_id"):
"""
try:
result = self.keystone.projects.create(project_info["name"], self.project_domain_name,
- _admin=project_info["_admin"])
+ _admin=project_info["_admin"],
+ quotas=project_info.get("quotas", {})
+ )
return result.id
except ClientException as e:
# self.logger.exception("Error during project creation using keystone: {}".format(e))
:return: None
"""
try:
- self.keystone.projects.update(project_id, name=project_info["name"], _admin=project_info["_admin"])
+ self.keystone.projects.update(project_id, name=project_info["name"],
+ _admin=project_info["_admin"],
+ quotas=project_info.get("quotas", {})
+ )
except ClientException as e:
# self.logger.exception("Error during project update using keystone: {}".format(e))
raise AuthconnOperationException("Error during project update using Keystone: {}".format(e))
schema_edit = None # to_override
multiproject = True # True if this Topic can be shared by several projects. Then it contains _admin.projects_read
+ default_quota = 500
+
# Alternative ID Fields for some Topics
alt_id_field = {
"projects": "name",
"roles": "name"
}
- def __init__(self, db, fs, msg):
+ def __init__(self, db, fs, msg, auth):
self.db = db
self.fs = fs
self.msg = msg
self.logger = logging.getLogger("nbi.engine")
+ self.auth = auth
@staticmethod
def id_field(topic, value):
return {}
return indata
+ def check_quota(self, session):
+ """
+ Check whether topic quota is exceeded by the given project
+ Used by relevant topics' 'new' function to decide whether or not creation of the new item should be allowed
+ :param projects: projects (tuple) for which quota should be checked
+ :param override: boolean. If true, don't raise ValidationError even though quota be exceeded
+ :return: None
+ :raise:
+ DbException if project not found
+ ValidationError if quota exceeded and not overridden
+ """
+ if session["force"] or session["admin"]:
+ return
+ projects = session["project_id"]
+ for project in projects:
+ proj = self.auth.get_project(project)
+ pid = proj["_id"]
+ quota = proj.get("quotas", {}).get(self.topic, self.default_quota)
+ count = self.db.count(self.topic, {"_admin.projects_read": pid})
+ if count >= quota:
+ name = proj["name"]
+ raise ValidationError("{} quota ({}) exceeded for project {} ({})".format(self.topic, quota, name, pid))
+
def _validate_input_new(self, input, force=False):
"""
Validates input user content for a new entry. It uses jsonschema. Some overrides will use pyangbind
op_id: operation id if this is asynchronous, None otherwise
"""
try:
+ if self.multiproject:
+ self.check_quota(session)
+
content = self._remove_envelop(indata)
# Override descriptor with query string kwargs
class DescriptorTopic(BaseTopic):
- def __init__(self, db, fs, msg):
- BaseTopic.__init__(self, db, fs, msg)
+ def __init__(self, db, fs, msg, auth):
+ BaseTopic.__init__(self, db, fs, msg, auth)
def check_conflict_on_edit(self, session, final_content, edit_content, _id):
super().check_conflict_on_edit(session, final_content, edit_content, _id)
"""
try:
+ # Check Quota
+ self.check_quota(session)
+
# _remove_envelop
if indata:
if "userDefinedData" in indata:
topic = "vnfds"
topic_msg = "vnfd"
- def __init__(self, db, fs, msg):
- DescriptorTopic.__init__(self, db, fs, msg)
+ def __init__(self, db, fs, msg, auth):
+ DescriptorTopic.__init__(self, db, fs, msg, auth)
@staticmethod
def _remove_envelop(indata=None):
topic = "nsds"
topic_msg = "nsd"
- def __init__(self, db, fs, msg):
- DescriptorTopic.__init__(self, db, fs, msg)
+ def __init__(self, db, fs, msg, auth):
+ DescriptorTopic.__init__(self, db, fs, msg, auth)
@staticmethod
def _remove_envelop(indata=None):
topic = "nsts"
topic_msg = "nst"
- def __init__(self, db, fs, msg):
- DescriptorTopic.__init__(self, db, fs, msg)
+ def __init__(self, db, fs, msg, auth):
+ DescriptorTopic.__init__(self, db, fs, msg, auth)
@staticmethod
def _remove_envelop(indata=None):
schema_new = pdu_new_schema
schema_edit = pdu_edit_schema
- def __init__(self, db, fs, msg):
- BaseTopic.__init__(self, db, fs, msg)
+ def __init__(self, db, fs, msg, auth):
+ BaseTopic.__init__(self, db, fs, msg, auth)
@staticmethod
def format_on_new(content, project_id=None, make_public=False):
self.write_lock = Lock()
# create one class per topic
for topic, topic_class in self.map_from_topic_to_class.items():
- if self.auth and topic_class in (UserTopicAuth, ProjectTopicAuth):
- self.map_topic[topic] = topic_class(self.db, self.fs, self.msg, self.auth)
- elif self.auth and topic_class == RoleTopicAuth:
+ # if self.auth and topic_class in (UserTopicAuth, ProjectTopicAuth):
+ # self.map_topic[topic] = topic_class(self.db, self.fs, self.msg, self.auth)
+ if self.auth and topic_class == RoleTopicAuth:
self.map_topic[topic] = topic_class(self.db, self.fs, self.msg, self.auth,
self.operations)
else:
- self.map_topic[topic] = topic_class(self.db, self.fs, self.msg)
+ self.map_topic[topic] = topic_class(self.db, self.fs, self.msg, self.auth)
self.map_topic["pm_jobs"] = PmJobsTopic(config["prometheus"].get("host"), config["prometheus"].get("port"))
except (DbException, FsException, MsgException) as e:
topic_msg = "ns"
schema_new = ns_instantiate
- def __init__(self, db, fs, msg):
- BaseTopic.__init__(self, db, fs, msg)
+ def __init__(self, db, fs, msg, auth):
+ BaseTopic.__init__(self, db, fs, msg, auth)
def _check_descriptor_dependencies(self, session, descriptor):
"""
"""
try:
+ step = "checking quotas"
+ self.check_quota(session)
+
step = "validating input parameters"
ns_request = self._remove_envelop(indata)
# Override descriptor with query string kwargs
topic = "vnfrs"
topic_msg = None
- def __init__(self, db, fs, msg):
- BaseTopic.__init__(self, db, fs, msg)
+ def __init__(self, db, fs, msg, auth):
+ BaseTopic.__init__(self, db, fs, msg, auth)
def delete(self, session, _id, dry_run=False):
raise EngineException("Method delete called directly", HTTPStatus.INTERNAL_SERVER_ERROR)
"terminate": None,
}
- def __init__(self, db, fs, msg):
- BaseTopic.__init__(self, db, fs, msg)
+ def __init__(self, db, fs, msg, auth):
+ BaseTopic.__init__(self, db, fs, msg, auth)
def _check_ns_operation(self, session, nsr, operation, indata):
"""
topic = "nsis"
topic_msg = "nsi"
- def __init__(self, db, fs, msg):
- BaseTopic.__init__(self, db, fs, msg)
- self.nsrTopic = NsrTopic(db, fs, msg)
+ def __init__(self, db, fs, msg, auth):
+ BaseTopic.__init__(self, db, fs, msg, auth)
+ self.nsrTopic = NsrTopic(db, fs, msg, auth)
@staticmethod
def _format_ns_request(ns_request):
"""
try:
+ step = "checking quotas"
+ self.check_quota(session)
+
step = ""
slice_request = self._remove_envelop(indata)
# Override descriptor with query string kwargs
"terminate": None
}
- def __init__(self, db, fs, msg):
- BaseTopic.__init__(self, db, fs, msg)
- self.nsi_NsLcmOpTopic = NsLcmOpTopic(self.db, self.fs, self.msg)
+ def __init__(self, db, fs, msg, auth):
+ BaseTopic.__init__(self, db, fs, msg, auth)
+ self.nsi_NsLcmOpTopic = NsLcmOpTopic(self.db, self.fs, self.msg, self.auth)
def _check_nsi_operation(self, session, nsir, operation, indata):
"""
}
# PROJECTS
+topics_with_quota = ["vnfds", "nsds", "nsts", "pdus", "nsrs", "nsis", "vim_accounts", "wim_accounts", "sdns"]
project_new_schema = {
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "New project schema for administrators",
"properties": {
"name": shortname_schema,
"admin": bool_schema,
+ "quotas": {
+ "type": "object",
+ "properties": {topic: integer0_schema for topic in topics_with_quota},
+ "additionalProperties": False
+ },
},
"required": ["name"],
"additionalProperties": False
"properties": {
"admin": bool_schema,
"name": shortname_schema, # To allow Project Name modification
+ "quotas": {
+ "type": "object",
+ "properties": {topic: {"oneOf": [integer0_schema, null_schema]} for topic in topics_with_quota},
+ "additionalProperties": False
+ },
},
"additionalProperties": False,
"minProperties": 1