diff options
Diffstat (limited to 'moonv4/moon_secrouter/moon_secrouter/api/route.py')
-rw-r--r-- | moonv4/moon_secrouter/moon_secrouter/api/route.py | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/moonv4/moon_secrouter/moon_secrouter/api/route.py b/moonv4/moon_secrouter/moon_secrouter/api/route.py new file mode 100644 index 00000000..ec79d96b --- /dev/null +++ b/moonv4/moon_secrouter/moon_secrouter/api/route.py @@ -0,0 +1,254 @@ +# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors +# This software is distributed under the terms and conditions of the 'Apache-2.0' +# license which can be found in the file 'LICENSE' in this package distribution +# or at 'http://www.apache.org/licenses/LICENSE-2.0'. + +import copy +import time +from oslo_log import log as logging +from moon_utilities.security_functions import call +from oslo_config import cfg +from moon_secrouter.api.generic import Status, Logs + +LOG = logging.getLogger(__name__) +CONF = cfg.CONF + +API = { + "orchestrator": ( + "add_container", + "delete_container", + "add_slave", + "get_slaves", + "delete_slave" + ), + # TODO (asteroide): need to check if some of those calls need (or not) to be called "update_" + "manager": ( + "get_subject_assignments", + "set_subject_assignment", + "delete_subject_assignment", + "get_object_assignments", + "set_object_assignment", + "delete_object_assignment", + "get_action_assignments", + "set_action_assignment", + "delete_action_assignment", + "get_subject_data", + "add_subject_data", + "delete_subject_data", + "get_object_data", + "add_object_data", + "delete_object_data", + "get_action_data", + "add_action_data", + "delete_action_data", + "get_subject_categories", + "set_subject_category", + "delete_subject_category", + "get_object_categories", + "set_object_category", + "delete_object_category", + "get_action_categories", + "set_action_category", + "delete_action_category", + "add_meta_rules", + "delete_meta_rules", + "get_meta_rules", + "set_meta_rules", + "get_models", + "add_model", + "delete_model", + "update_model", + "get_pdp", + "add_pdp", + "delete_pdp", + "update_pdp", + "get_subjects", + "set_subject", + "delete_subject", + "get_objects", + "set_object", + "delete_object", + "get_actions", + "set_action", + "delete_action", + "get_policies", + "add_policy", + "delete_policy", + "update_policy", + "get_subject_assignments", + "update_subject_assignment", + "delete_subject_assignment", + "get_object_assignments", + "update_object_assignment", + "delete_object_assignment", + "get_action_assignments", + "update_action_assignment", + "delete_action_assignment", + "get_rules", + "add_rule", + "delete_rule" + ), + "function": ( + "authz", + ), +} + + +class Cache(object): + + # TODO (asteroide): set cache integer in CONF file + __UPDATE_INTERVAL = 300 + __CONTAINERS = {} + __LAST_UPDATE = 0 + + def __update_container(self): + containers = call("orchestrator", method="get_container", ctx={}, args={}) + LOG.info("container={}".format(containers)) + for key, value in containers["containers"].items(): + self.__CONTAINERS[key] = value + + def update(self, component=None): + self.__update_container() + + @property + def containers(self): + """intra_extensions cache + example of content : + { + "pdp_uuid1": "component_uuid1", + "pdp_uuid2": "component_uuid2", + } + :return: + """ + current_time = time.time() + if self.__LAST_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_container() + self.__LAST_UPDATE = current_time + return self.__CONTAINERS + + +CACHE = Cache() + + +class Router(object): + """ + Route requests to all components. + """ + + __version__ = "0.1.0" + + def __init__(self, add_master_cnx): + if CONF.slave.slave_name and add_master_cnx: + result = call('security_router', method="route", + ctx={ + "name": CONF.slave.slave_name, + "description": CONF.slave.slave_name, + "call_master": True, + "method": "add_slave"}, args={}) + if "result" in result and not result["result"]: + LOG.error("An error occurred when sending slave name {} {}".format( + CONF.slave.slave_name, result + )) + self.slave_id = list(result['slaves'].keys())[0] + result = call('security_router', method="route", + ctx={ + "name": CONF.slave.slave_name, + "description": CONF.slave.slave_name, + "call_master": True, + "method": "get_slaves"}, args={}) + if "result" in result and not result["result"]: + LOG.error("An error occurred when receiving slave names {} {}".format( + CONF.slave.slave_name, result + )) + LOG.info("SLAVES: {}".format(result)) + + def delete(self): + if CONF.slave.slave_name and self.slave_id: + result = call('security_router', method="route", + ctx={ + "name": CONF.slave.slave_name, + "description": CONF.slave.slave_name, + "call_master": True, + "method": "delete_slave", + "id": self.slave_id}, args={}) + if "result" in result and not result["result"]: + LOG.error("An error occurred when sending slave name {} {}".format( + CONF.slave.slave_name, result + )) + LOG.info("SLAVE CONNECTION ENDED!") + LOG.info(result) + + @staticmethod + def __get_first_container(keystone_project_id): + for container_id, container_value, in CACHE.containers.items(): + if container_value: + if container_value[0]["keystone_project_id"] == keystone_project_id: + return container_value[0]["container_id"] + + @staticmethod + def check_pdp(ctx): + _ctx = copy.deepcopy(ctx) + if CONF.slave.slave_name: + _ctx['call_master'] = True + ext = call("moon_manager", method="get_pdp", ctx=_ctx, args={}) + if "error" not in ext: + return True + + def send_update(self, api, ctx={}, args={}): + # TODO (asteroide): add threads here + if not CONF.slave.slave_name: + # Note (asteroide): + # if adding or setting an element: do nothing + # if updating or deleting an element: force deletion in the slave + if "update_" in api or "delete_" in api: + for slave_id, slave_dict in call("orchestrator", method="get_slaves", ctx={}, args={})['slaves'].items(): + LOG.info('send_update slave_id={}'.format(slave_id)) + LOG.info('send_update slave_dict={}'.format(slave_dict)) + ctx['method'] = api.replace("update", "delete") + # TODO (asteroide): force data_id to None to force the deletion in the slave + result = call("security_router_"+slave_dict['name'], method="route", ctx=ctx, args=args) + if "result" in result and not result["result"]: + LOG.error("An error occurred when sending update to {} {}".format( + "security_router_"+slave_dict['name'], result + )) + + def route(self, ctx, args): + """Route the request to the right endpoint + + :param ctx: dictionary depending of the real destination + :param args: dictionary depending of the real destination + :return: dictionary depending of the real destination + """ + if ctx["method"] == "get_status": + return Status().get_status(ctx=ctx, args=args) + if ctx["method"] == "get_logs": + return Logs().get_logs(ctx=ctx, args=args) + for component in API: + if ctx["method"] in API[component]: + if component == "orchestrator": + return call(component, method=ctx["method"], ctx=ctx, args=args) + if component == "manager": + LOG.info("Call Manager {}".format(ctx)) + result = call("moon_manager", method=ctx["method"], ctx=ctx, args=args) + self.send_update(api=ctx["method"], ctx=ctx, args=args) + return result + if component == "function": + if self.check_pdp(ctx): + LOG.info("Tenant ID={}".format(ctx['id'])) + pdp_container = self.__get_first_container(ctx['id']) + LOG.info("pdp_container={}".format(pdp_container)) + # TODO (asteroide): call the first security function through a notification + # and not an RPC call (need to play with ID in context) + result = call(pdp_container, method=ctx["method"], ctx=ctx, args=args) + return result + return {"result": False, + "error": {'code': 500, 'title': 'Moon Error', 'description': "Function component not found."}, + "pdp_id": ctx["id"], + "ctx": ctx, "args": args} + + # TODO (asteroide): must raise an exception here ? + return {"result": False, + "error": {'code': 500, 'title': 'Moon Error', 'description': "Endpoint method not found."}, + "intra_extension_id": ctx["id"], + "ctx": ctx, "args": args} + |