diff options
Diffstat (limited to 'moonv4/moon_utilities')
22 files changed, 1528 insertions, 666 deletions
diff --git a/moonv4/moon_utilities/Changelog b/moonv4/moon_utilities/Changelog index e39a8b53..952c2aa1 100644 --- a/moonv4/moon_utilities/Changelog +++ b/moonv4/moon_utilities/Changelog @@ -35,3 +35,31 @@ CHANGES ----- - Add authentication features for interface +1.3.0 +----- +- Add cache functionality + +1.3.1 +----- +- Delete Oslo config possibilities + +1.3.2 +----- +- Delete Oslo logging and config + +1.3.3 +----- +- Update the cache + +1.3.4 +----- +- Fix a bug on the connection between interface and authz + +1.4.0 +----- +- Add a waiting loop when the Keystone server is not currently available + +1.4.1 +----- +- Cleanup moon_utilities code + diff --git a/moonv4/moon_utilities/LICENSE b/moonv4/moon_utilities/LICENSE index 4143aac2..d6456956 100644 --- a/moonv4/moon_utilities/LICENSE +++ b/moonv4/moon_utilities/LICENSE @@ -174,31 +174,29 @@ incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ---- License for python-keystoneclient versions prior to 2.1 --- - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of this project nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/moonv4/moon_utilities/README.md b/moonv4/moon_utilities/README.md new file mode 100644 index 00000000..bbc1d458 --- /dev/null +++ b/moonv4/moon_utilities/README.md @@ -0,0 +1,33 @@ +# Moon Python Utilities Package +This package contains the core module for the Moon project. +It is designed to provide authorization feature to all OpenStack components. + +For any other information, refer to the parent project: + + https://git.opnfv.org/moon + +moon_utilities is a common Python lib for other Moon Python packages + +## Build +### Build Python Package +```bash +cd ${MOON_HOME}/moonv4/moon_utilities +python3 setup.py sdist bdist_wheel +``` + +### Push Python Package to PIP +```bash +cd ${MOON_HOME}/moonv4/moon_utilities +gpg --detach-sign -u "${GPG_ID}" -a dist/moon_utilities-X.Y.Z-py3-none-any.whl +gpg --detach-sign -u "${GPG_ID}" -a dist/moon_utilities-X.Y.Z.tar.gz +twine upload dist/moon_db-X.Y.Z-py3-none-any.whl dist/moon_utilities-X.Y.Z-py3-none-any.whl.asc +twine upload dist/moon_db-X.Y.Z.tar.gz dist/moon_uutilities-X.Y.Z.tar.gz.asc +``` + +## Test +### Python Unit Test +launch Docker for Python unit tests +```bash +cd ${MOON_HOME}/moonv4/moon_utilities +docker run --rm --volume $(pwd):/data wukongsun/moon_python_unit_test:latest +``` diff --git a/moonv4/moon_utilities/README.rst b/moonv4/moon_utilities/README.rst deleted file mode 100644 index ded4e99a..00000000 --- a/moonv4/moon_utilities/README.rst +++ /dev/null @@ -1,9 +0,0 @@ -Core module for the Moon project -================================ - -This package contains the core module for the Moon project -It is designed to provide authorization features to all OpenStack components. - -For any other information, refer to the parent project: - - https://git.opnfv.org/moon diff --git a/moonv4/moon_utilities/moon_utilities/__init__.py b/moonv4/moon_utilities/moon_utilities/__init__.py index 2c7f8f5c..e3ad9307 100644 --- a/moonv4/moon_utilities/moon_utilities/__init__.py +++ b/moonv4/moon_utilities/moon_utilities/__init__.py @@ -3,4 +3,4 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -__version__ = "1.2.0" +__version__ = "1.4.1" diff --git a/moonv4/moon_utilities/moon_utilities/cache.py b/moonv4/moon_utilities/moon_utilities/cache.py new file mode 100644 index 00000000..8c6ee3bf --- /dev/null +++ b/moonv4/moon_utilities/moon_utilities/cache.py @@ -0,0 +1,543 @@ +import logging +import time +import requests +from uuid import uuid4 +from moon_utilities import configuration, exceptions + +LOG = logging.getLogger("moon.utilities.cache") + + +class Cache(object): + # TODO (asteroide): set cache integer in CONF file + ''' + [NOTE] Propose to define the following variables inside the init method + as defining them out side the init, will be treated as private static variables + and keep tracks with any changes done anywhere + for more info : you can check https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables + ''' + __UPDATE_INTERVAL = 10 + + __CONTAINERS = {} + __CONTAINERS_UPDATE = 0 + + __CONTAINER_CHAINING_UPDATE = 0 + __CONTAINER_CHAINING = {} + + __PDP = {} + __PDP_UPDATE = 0 + + __POLICIES = {} + __POLICIES_UPDATE = 0 + + __MODELS = {} + __MODELS_UPDATE = 0 + + __SUBJECTS = {} + __OBJECTS = {} + __ACTIONS = {} + + __SUBJECT_ASSIGNMENTS = {} + __OBJECT_ASSIGNMENTS = {} + __ACTION_ASSIGNMENTS = {} + + __SUBJECT_CATEGORIES = {} + __SUBJECT_CATEGORIES_UPDATE = 0 + __OBJECT_CATEGORIES = {} + __OBJECT_CATEGORIES_UPDATE = 0 + __ACTION_CATEGORIES = {} + __ACTION_CATEGORIES_UPDATE = 0 + + __META_RULES = {} + __META_RULES_UPDATE = 0 + + __RULES = {} + __RULES_UPDATE = 0 + + __AUTHZ_REQUESTS = {} + + def __init__(self): + self.manager_url = "{}://{}:{}".format( + configuration.get_components()['manager'].get('protocol', 'http'), + configuration.get_components()['manager']['hostname'], + configuration.get_components()['manager']['port'] + ) + self.orchestrator_url = "{}://{}:{}".format( + configuration.get_components()['orchestrator'].get('protocol', 'http'), + configuration.get_components()['orchestrator']['hostname'], + configuration.get_components()['orchestrator']['port'] + ) + + def update(self): + self.__update_container() + self.__update_pdp() + self.__update_policies() + self.__update_models() + for key, value in self.__PDP.items(): + # LOG.info("Updating container_chaining with {}".format(value["keystone_project_id"])) + self.__update_container_chaining(value["keystone_project_id"]) + + @property + def authz_requests(self): + return self.__AUTHZ_REQUESTS + + # perimeter functions + + @property + def subjects(self): + return self.__SUBJECTS + + def update_subjects(self, policy_id=None): + req = requests.get("{}/policies/{}/subjects".format( + self.manager_url, policy_id)) + self.__SUBJECTS[policy_id] = req.json()['subjects'] + + def get_subject(self, policy_id, name): + try: + for _subject_id, _subject_dict in self.__SUBJECTS[policy_id].items(): + if _subject_dict["name"] == name: + return _subject_id + except KeyError: + pass + self.update_subjects(policy_id) + for _subject_id, _subject_dict in self.__SUBJECTS[policy_id].items(): + if _subject_dict["name"] == name: + return _subject_id + raise exceptions.SubjectUnknown("Cannot find subject {}".format(name)) + + @property + def objects(self): + return self.__OBJECTS + + def update_objects(self, policy_id=None): + req = requests.get("{}/policies/{}/objects".format( + self.manager_url, policy_id)) + self.__OBJECTS[policy_id] = req.json()['objects'] + + def get_object(self, policy_id, name): + try: + for _object_id, _object_dict in self.__OBJECTS[policy_id].items(): + if _object_dict["name"] == name: + return _object_id + except KeyError: + pass + self.update_objects(policy_id) + for _object_id, _object_dict in self.__OBJECTS[policy_id].items(): + if _object_dict["name"] == name: + return _object_id + raise exceptions.SubjectUnknown("Cannot find object {}".format(name)) + + @property + def actions(self): + return self.__ACTIONS + + def update_actions(self, policy_id=None): + req = requests.get("{}/policies/{}/actions".format( + self.manager_url, policy_id)) + self.__ACTIONS[policy_id] = req.json()['actions'] + + def get_action(self, policy_id, name): + try: + for _action_id, _action_dict in self.__ACTIONS[policy_id].items(): + if _action_dict["name"] == name: + return _action_id + except KeyError: + pass + self.update_actions(policy_id) + for _action_id, _action_dict in self.__ACTIONS[policy_id].items(): + if _action_dict["name"] == name: + return _action_id + raise exceptions.SubjectUnknown("Cannot find action {}".format(name)) + + # meta_rule functions + + @property + def meta_rules(self): + current_time = time.time() + if self.__META_RULES_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_meta_rules() + self.__META_RULES_UPDATE = current_time + return self.__META_RULES + + def __update_meta_rules(self): + req = requests.get("{}/meta_rules".format(self.manager_url)) + self.__META_RULES = req.json()['meta_rules'] + + # rule functions + + @property + def rules(self): + current_time = time.time() + if self.__RULES_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_rules() + self.__RULES_UPDATE = current_time + return self.__RULES + + def __update_rules(self): + for policy_id in self.__POLICIES: + LOG.info("Get {}".format("{}/policies/{}/rules".format( + self.manager_url, policy_id))) + req = requests.get("{}/policies/{}/rules".format( + self.manager_url, policy_id)) + self.__RULES[policy_id] = req.json()['rules'] + LOG.info("UPDATE RULES {}".format(self.__RULES)) + + # assignment functions + + @property + def subject_assignments(self): + return self.__SUBJECT_ASSIGNMENTS + + def update_subject_assignments(self, policy_id=None, perimeter_id=None): + if perimeter_id: + req = requests.get("{}/policies/{}/subject_assignments/{}".format( + self.manager_url, policy_id, perimeter_id)) + else: + req = requests.get("{}/policies/{}/subject_assignments".format( + self.manager_url, policy_id)) + if policy_id not in self.__SUBJECT_ASSIGNMENTS: + self.__SUBJECT_ASSIGNMENTS[policy_id] = {} + self.__SUBJECT_ASSIGNMENTS[policy_id].update( + req.json()['subject_assignments']) + + def get_subject_assignments(self, policy_id, perimeter_id, category_id): + if policy_id not in self.subject_assignments: + self.update_subject_assignments(policy_id, perimeter_id) + ''' + [NOTE] invalid condition for testing existence of policy_id + because update_subject_assignments function already add an empty object + with the given policy_id and then assign the response to it + as mentioned in these lines of code (line 191,192) + + Note: the same condition applied for the object,action assignment + line 234, 260 + ''' + if policy_id not in self.subject_assignments: + raise Exception("Cannot found the policy {}".format(policy_id)) + for key, value in self.subject_assignments[policy_id].items(): + if perimeter_id == value['subject_id'] and category_id == value['category_id']: + return value['assignments'] + return [] + + @property + def object_assignments(self): + return self.__OBJECT_ASSIGNMENTS + + def update_object_assignments(self, policy_id=None, perimeter_id=None): + if perimeter_id: + req = requests.get("{}/policies/{}/object_assignments/{}".format( + self.manager_url, policy_id, perimeter_id)) + else: + req = requests.get("{}/policies/{}/object_assignments".format( + self.manager_url, policy_id)) + if policy_id not in self.__OBJECT_ASSIGNMENTS: + self.__OBJECT_ASSIGNMENTS[policy_id] = {} + self.__OBJECT_ASSIGNMENTS[policy_id].update( + req.json()['object_assignments']) + + def get_object_assignments(self, policy_id, perimeter_id, category_id): + if policy_id not in self.object_assignments: + self.update_object_assignments(policy_id, perimeter_id) + if policy_id not in self.object_assignments: + raise Exception("Cannot found the policy {}".format(policy_id)) + for key, value in self.object_assignments[policy_id].items(): + if perimeter_id == value['object_id'] and category_id == value['category_id']: + return value['assignments'] + return [] + + @property + def action_assignments(self): + return self.__ACTION_ASSIGNMENTS + + def update_action_assignments(self, policy_id=None, perimeter_id=None): + if perimeter_id: + req = requests.get("{}/policies/{}/action_assignments/{}".format( + self.manager_url, policy_id, perimeter_id)) + else: + req = requests.get("{}/policies/{}/action_assignments".format( + self.manager_url, policy_id)) + if policy_id not in self.__ACTION_ASSIGNMENTS: + self.__ACTION_ASSIGNMENTS[policy_id] = {} + self.__ACTION_ASSIGNMENTS[policy_id].update( + req.json()['action_assignments']) + + def get_action_assignments(self, policy_id, perimeter_id, category_id): + if policy_id not in self.action_assignments: + self.update_action_assignments(policy_id, perimeter_id) + if policy_id not in self.action_assignments: + raise Exception("Cannot found the policy {}".format(policy_id)) + for key, value in self.action_assignments[policy_id].items(): + if perimeter_id == value['action_id'] and category_id == value['category_id']: + return value['assignments'] + return [] + + # category functions + + @property + def subject_categories(self): + current_time = time.time() + if self.__SUBJECT_CATEGORIES_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_subject_categories() + self.__SUBJECT_CATEGORIES_UPDATE = current_time + return self.__SUBJECT_CATEGORIES + + def __update_subject_categories(self): + req = requests.get("{}/policies/subject_categories".format( + self.manager_url)) + self.__SUBJECT_CATEGORIES.update(req.json()['subject_categories']) + + @property + def object_categories(self): + current_time = time.time() + if self.__OBJECT_CATEGORIES_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_object_categories() + self.__OBJECT_CATEGORIES_UPDATE = current_time + return self.__OBJECT_CATEGORIES + + def __update_object_categories(self): + req = requests.get("{}/policies/object_categories".format( + self.manager_url)) + self.__OBJECT_CATEGORIES.update(req.json()['object_categories']) + + @property + def action_categories(self): + current_time = time.time() + if self.__ACTION_CATEGORIES_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_action_categories() + self.__ACTION_CATEGORIES_UPDATE = current_time + return self.__ACTION_CATEGORIES + + def __update_action_categories(self): + req = requests.get("{}/policies/action_categories".format( + self.manager_url)) + self.__ACTION_CATEGORIES.update(req.json()['action_categories']) + + # PDP functions + + def __update_pdp(self): + req = requests.get("{}/pdp".format(self.manager_url)) + pdp = req.json() + for _pdp in pdp["pdps"].values(): + if _pdp['keystone_project_id'] not in self.__CONTAINER_CHAINING: + self.__CONTAINER_CHAINING[_pdp['keystone_project_id']] = {} + # Note (asteroide): force update of chaining + self.__update_container_chaining(_pdp['keystone_project_id']) + for key, value in pdp["pdps"].items(): + self.__PDP[key] = value + + @property + def pdp(self): + """Policy Decision Point + Example of content: + { + "pdp_id": { + "keystone_project_id": "keystone_project_id", + "name": "pdp1", + "description": "test", + "security_pipeline": [ + "policy_id" + ] + } + } + + :return: + """ + current_time = time.time() + if self.__PDP_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_pdp() + self.__PDP_UPDATE = current_time + return self.__PDP + + # policy functions + def __update_policies(self): + req = requests.get("{}/policies".format(self.manager_url)) + policies = req.json() + for key, value in policies["policies"].items(): + self.__POLICIES[key] = value + + @property + def policies(self): + current_time = time.time() + if self.__POLICIES_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_policies() + self.__POLICIES_UPDATE = current_time + return self.__POLICIES + + # model functions + + def __update_models(self): + req = requests.get("{}/models".format(self.manager_url)) + models = req.json() + for key, value in models["models"].items(): + self.__MODELS[key] = value + + @property + def models(self): + current_time = time.time() + if self.__MODELS_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_models() + self.__MODELS_UPDATE = current_time + return self.__MODELS + + # helper functions + + def get_policy_from_meta_rules(self, meta_rule_id): + for pdp_key, pdp_value in self.pdp.items(): + for policy_id in pdp_value["security_pipeline"]: + model_id = self.policies[policy_id]["model_id"] + if meta_rule_id in self.models[model_id]["meta_rules"]: + return policy_id + + def get_pdp_from_keystone_project(self, keystone_project_id): + for pdp_key, pdp_value in self.pdp.items(): + if keystone_project_id == pdp_value["keystone_project_id"]: + return pdp_key + + def get_keystone_project_id_from_policy_id(self, policy_id): + for pdp_key, pdp_value in self.pdp.items(): + if policy_id in pdp_value["security_pipeline"]: + return pdp_value["keystone_project_id"] + # for policy_id in pdp_value["security_pipeline"]: + # model_id = self.policies[policy_id]["model_id"] + # if meta_rule_id in self.models[model_id]["meta_rules"]: + # return pdp_value["keystone_project_id"] + + def get_containers_from_keystone_project_id(self, keystone_project_id, + meta_rule_id=None): + for container_id, container_values in self.containers.items(): + for container_value in container_values: + if 'keystone_project_id' not in container_value: + continue + if container_value['keystone_project_id'] == keystone_project_id: + if not meta_rule_id: + yield container_id, container_value + elif container_value.get('meta_rule_id') == meta_rule_id: + yield container_id, container_value + break + + # containers functions + + def __update_container(self): + req = requests.get("{}/pods".format(self.orchestrator_url)) + pods = req.json() + for key, value in pods["pods"].items(): + # if key not in self.__CONTAINERS: + self.__CONTAINERS[key] = value + # else: + # for container in value: + # self.__CONTAINERS[key].update(value) + + def add_container(self, container_data): + """Add a new container in the cache + + :param container_data: dictionary with information for the container + Example: + { + "name": name, + "hostname": name, + "port": { + "PrivatePort": tcp_port, + "Type": "tcp", + "IP": "0.0.0.0", + "PublicPort": tcp_port + }, + "keystone_project_id": uuid, + "pdp_id": self.CACHE.get_pdp_from_keystone_project(uuid), + "meta_rule_id": meta_rule_id, + "container_name": container_name, + "plugin_name": plugin_name + "container_id": "container_id" + } + + :return: + """ + self.__CONTAINERS[uuid4().hex] = { + "keystone_project_id": container_data['keystone_project_id'], + "name": container_data['name'], + "container_id": container_data['container_id'], + "hostname": container_data['name'], + "policy_id": container_data['policy_id'], + "meta_rule_id": container_data['meta_rule_id'], + "port": [ + { + "PublicPort": container_data['port']["PublicPort"], + "Type": container_data['port']["Type"], + "IP": container_data['port']["IP"], + "PrivatePort": container_data['port']["PrivatePort"] + } + ], + "genre": container_data['plugin_name'] + } + self.__update_container_chaining(self.get_keystone_project_id_from_policy_id(container_data['policy_id'])) + + @property + def containers(self): + """Containers cache + example of content : + { + "policy_uuid1": "component_hostname1", + "policy_uuid2": "component_hostname2", + } + :return: + """ + current_time = time.time() + if self.__CONTAINERS_UPDATE + self.__UPDATE_INTERVAL < current_time: + self.__update_container() + self.__CONTAINERS_UPDATE = current_time + return self.__CONTAINERS + + @property + def container_chaining(self): + """Cache for mapping Keystone Project ID with meta_rule ID and container ID + Example of content: + { + "keystone_project_id": [ + { + "container_id": "container_id", + "genre": "genre", + "policy_id": "policy_id", + "meta_rule_id": "meta_rule_id", + } + ] + } + + :return: + """ + current_time = time.time() + if self.__CONTAINER_CHAINING_UPDATE + self.__UPDATE_INTERVAL < current_time: + for key, value in self.pdp.items(): + if not value["keystone_project_id"]: + continue + self.__update_container_chaining(value["keystone_project_id"]) + self.__CONTAINER_CHAINING_UPDATE = current_time + LOG.info(self.__CONTAINER_CHAINING_UPDATE) + return self.__CONTAINER_CHAINING + + def __update_container_chaining(self, keystone_project_id): + container_ids = [] + for pdp_id, pdp_value, in self.__PDP.items(): + if pdp_value: + if pdp_value["keystone_project_id"] == keystone_project_id: + for policy_id in pdp_value["security_pipeline"]: + model_id = self.__POLICIES[policy_id]['model_id'] + for meta_rule_id in self.__MODELS[model_id]["meta_rules"]: + for container_id, container_value in self.get_containers_from_keystone_project_id( + keystone_project_id, + meta_rule_id + ): + _raw = requests.get("{}/pods/{}".format( + self.orchestrator_url, container_value["name"]) + ) + LOG.debug("_raw={}".format(_raw.text)) + container_ids.append( + { + "container_id": container_value["name"], + "genre": container_value["genre"], + "policy_id": policy_id, + "meta_rule_id": meta_rule_id, + "hostname": container_value["name"], + "hostip": "127.0.0.1", + "port": container_value["port"], + } + ) + self.__CONTAINER_CHAINING[keystone_project_id] = container_ids + diff --git a/moonv4/moon_utilities/moon_utilities/configuration.py b/moonv4/moon_utilities/moon_utilities/configuration.py index 32eeff13..cda75de5 100644 --- a/moonv4/moon_utilities/moon_utilities/configuration.py +++ b/moonv4/moon_utilities/moon_utilities/configuration.py @@ -4,15 +4,11 @@ # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -import copy import base64 import json import requests import logging import logging.config -# from oslo_log import log as logging -from oslo_config import cfg -# import oslo_messaging from moon_utilities import exceptions LOG = logging.getLogger("moon.utilities") @@ -21,8 +17,6 @@ CONSUL_HOST = "consul" CONSUL_PORT = "8500" DATABASE = "database" -SLAVE = "slave" -MESSENGER = "messenger" KEYSTONE = "keystone" DOCKER = "docker" COMPONENTS = "components" @@ -33,11 +27,6 @@ def init_logging(): logging.config.dictConfig(config['logging']) -def init_oslo_config(): - cfg.CONF.transport_url = get_configuration("messenger")['messenger']['url'] - cfg.CONF.rpc_response_timeout = 5 - - def increment_port(): components_port_start = int(get_configuration("components_port_start")['components_port_start']) components_port_start += 1 @@ -53,8 +42,8 @@ def get_configuration(key): url = "http://{}:{}/v1/kv/{}".format(CONSUL_HOST, CONSUL_PORT, key) req = requests.get(url) if req.status_code != 200: - LOG.info("url={}".format(url)) - raise exceptions.ConsulComponentNotFound + LOG.error("url={}".format(url)) + raise exceptions.ConsulComponentNotFound("error={}: {}".format(req.status_code, req.text)) data = req.json() if len(data) == 1: data = data[0] @@ -123,4 +112,3 @@ def get_components(): init_logging() -init_oslo_config() diff --git a/moonv4/moon_utilities/moon_utilities/exceptions.py b/moonv4/moon_utilities/moon_utilities/exceptions.py index ba5ecf46..eb606432 100644 --- a/moonv4/moon_utilities/moon_utilities/exceptions.py +++ b/moonv4/moon_utilities/moon_utilities/exceptions.py @@ -138,26 +138,6 @@ class ModelExisting(MoonError): logger = "Error" -class RootExtensionUnknown(IntraExtensionUnknown): - description = _("The root_extension is unknown.") - code = 400 - title = 'Root Extension Unknown' - logger = "Error" - - -class RootPDPNotInitialized(IntraExtensionException): - description = _("The root_extension is not initialized.") - code = 400 - title = 'Root Extension Not Initialized' - logger = "Error" - - -class IntraExtensionCreationError(IntraExtensionException): - description = _("The arguments for the creation of this Extension were malformed.") - code = 400 - title = 'Intra Extension Creation Error' - - # Authz exceptions class AuthzException(MoonError): diff --git a/moonv4/moon_utilities/moon_utilities/get_os_apis.py b/moonv4/moon_utilities/moon_utilities/get_os_apis.py deleted file mode 100644 index dea2a878..00000000 --- a/moonv4/moon_utilities/moon_utilities/get_os_apis.py +++ /dev/null @@ -1,122 +0,0 @@ -import json -import logging -import requests -import argparse - -URLS = { - "keystone": "https://api.github.com/repos/openstack/keystone/contents/api-ref/source/v3", - "nova": "https://api.github.com/repos/openstack/nova/contents/api-ref/source", - "neutron": "https://api.github.com/repos/openstack/neutron-lib/contents/api-ref/source/v2", - "glance": "https://api.github.com/repos/openstack/glance/contents/api-ref/source/v2", - "swift": "https://api.github.com/repos/openstack/swift/contents/api-ref/source", - "cinder": "https://api.github.com/repos/openstack/cinder/contents/api-ref/source/v3", - -} - -logger = None - -USER = "" -PASS = "" - - -def init(): - global logger, USER, PASS - parser = argparse.ArgumentParser() - parser.add_argument("--verbose", "-v", action='store_true', help="verbose mode") - parser.add_argument("--debug", "-d", action='store_true', help="debug mode") - parser.add_argument("--format", "-f", help="Output format (txt, json)", default="json") - parser.add_argument("--output", "-o", help="Output filename") - parser.add_argument("--credentials", "-c", help="Github credential filename (inside format user:pass)") - args = parser.parse_args() - - FORMAT = '%(levelname)s %(message)s' - - if args.verbose: - logging.basicConfig( - format=FORMAT, - level=logging.INFO) - elif args.debug: - logging.basicConfig( - format=FORMAT, - level=logging.DEBUG) - else: - logging.basicConfig( - format=FORMAT, - level=logging.WARNING) - - if args.credentials: - cred = open(args.credentials).read() - USER = cred.split(":")[0] - PASS = cred.split(":")[1] - - logger = logging.getLogger(__name__) - - return args - - -def get_api_item(url): - if USER: - r = requests.get(url, auth=(USER, PASS)) - else: - r = requests.get(url) - items = [] - for line in r.text.splitlines(): - if ".. rest_method::" in line: - items.append(line.replace(".. rest_method::", "").strip()) - logger.debug("\n\t".join(items)) - return items - - -def get_content(key, args): - logger.info("Analysing {}".format(key)) - if USER: - r = requests.get(URLS[key], auth=(USER, PASS)) - else: - r = requests.get(URLS[key]) - data = r.json() - results = {} - for item in data: - try: - logger.debug("{} {}".format(item['name'], item['download_url'])) - if item['type'] == "file" and ".inc" in item['name']: - results[item['name'].replace(".inc", "")] = get_api_item(item['download_url']) - except TypeError: - logger.error("Error with {}".format(item)) - except requests.exceptions.MissingSchema: - logger.error("MissingSchema error {}".format(item)) - return results - - -def to_str(results): - output = "" - for key in results: - output += "{}\n".format(key) - for item in results[key]: - output += "\t{}\n".format(item) - for value in results[key][item]: - output += "\t\t{}\n".format(value) - return output - - -def save(results, args): - if args.output: - if args.format == 'json': - json.dump(results, open(args.output, "w"), indent=4) - elif args.format == 'txt': - open(args.output, "w").write(to_str(results)) - else: - if args.format == 'json': - print(json.dumps(results, indent=4)) - elif args.format in ('txt', 'text'): - print(to_str(results)) - - -def main(): - args = init() - results = {} - for key in URLS: - results[key] = get_content(key, args) - save(results, args) - -if __name__ == "__main__": - main()
\ No newline at end of file diff --git a/moonv4/moon_utilities/moon_utilities/misc.py b/moonv4/moon_utilities/moon_utilities/misc.py index d13b4511..b83523c3 100644 --- a/moonv4/moon_utilities/moon_utilities/misc.py +++ b/moonv4/moon_utilities/moon_utilities/misc.py @@ -4,28 +4,18 @@ # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -import os -import re -import types -import requests -from oslo_log import log as logging -from oslo_config import cfg -import oslo_messaging -from moon_utilities import exceptions -from oslo_config.cfg import ConfigOpts +import logging +import random LOG = logging.getLogger(__name__) -CONF = cfg.CONF def get_uuid_from_name(name, elements, **kwargs): - LOG.error("get_uuid_from_name {} {} {}".format(name, elements, kwargs)) for element in elements: if type(elements[element]) is dict and elements[element].get('name') == name: if kwargs: for args in kwargs: if elements[element].get(args) != kwargs[args]: - LOG.error("get_uuid_from_name2 {} {} {}".format(args, elements[element].get(args), kwargs[args])) return else: return element @@ -45,3 +35,108 @@ def get_name_from_uuid(uuid, elements, **kwargs): else: return elements[element].get('name') + +def get_random_name(): + _list = ( + "windy", + "vengeful", + "precious", + "vivacious", + "quiet", + "confused", + "exultant", + "impossible", + "thick", + "obsolete", + "piquant", + "fanatical", + "tame", + "perfect", + "animated", + "dark", + "stimulating", + "drunk", + "depressed", + "fumbling", + "like", + "undesirable", + "spurious", + "subsequent", + "spiteful", + "last", + "stale", + "hulking", + "giddy", + "minor", + "careful", + "possessive", + "gullible", + "fragile", + "divergent", + "ill-informed", + "false", + "jumpy", + "damaged", + "likeable", + "volatile", + "handsomely", + "wet", + "long-term", + "pretty", + "taboo", + "normal", + "magnificent", + "nutty", + "puzzling", + "small", + "kind", + "devilish", + "chubby", + "paltry", + "cultured", + "old", + "defective", + "hanging", + "innocent", + "jagged", + "economic", + "good", + "sulky", + "real", + "bent", + "shut", + "furry", + "terrific", + "hollow", + "terrible", + "mammoth", + "pleasant", + "scared", + "obnoxious", + "absorbing", + "imported", + "infamous", + "grieving", + "ill-fated", + "mighty", + "handy", + "comfortable", + "astonishing", + "brown", + "assorted", + "wrong", + "unsightly", + "spooky", + "delightful", + "acid", + "inconclusive", + "mere", + "careless", + "historical", + "flashy", + "squealing", + "quarrelsome", + "empty", + "long", + ) + return random.choice(_list) diff --git a/moonv4/moon_utilities/moon_utilities/options.py b/moonv4/moon_utilities/moon_utilities/options.py deleted file mode 100644 index 8b8ccca4..00000000 --- a/moonv4/moon_utilities/moon_utilities/options.py +++ /dev/null @@ -1,300 +0,0 @@ -# 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 os -import sys -from oslo_config import cfg -from oslo_log import log as logging -from moon_utilities import __version__ - -LOG = logging.getLogger(__name__) -CONF = cfg.CONF - -__CWD__ = os.path.dirname(os.path.abspath(__file__)) - - -def configure(domain="moon", version=__version__, usage=""): - # FIXME (dthom): put DEBUG as default log level doesn't work - extra_log_level_defaults = [ - '{}=DEBUG'.format(__name__), - ] - # LOG.setLevel(logging.DEBUG) - logging.set_defaults( - default_log_levels=logging.get_default_log_levels() + extra_log_level_defaults) - - logging.register_options(CONF) - logging.setup(CONF, domain) - - CONF.register_opts(get_opts()) - - # rabbit_group = cfg.OptGroup(name='messenger', - # title='Messenger options') - # CONF.register_group(rabbit_group) - # CONF.register_opts(get_messenger_opts(), group="messenger") - - slave_group = cfg.OptGroup(name='slave', - title='Messenger options') - CONF.register_group(slave_group) - CONF.register_opts(get_slave_opts(), group="slave") - - database_group = cfg.OptGroup(name='database', - title='Database options') - CONF.register_group(database_group) - CONF.register_opts(get_database_opts(), group="database") - - database_configuration_group = cfg.OptGroup(name='database_configuration', - title='Database configuration options') - CONF.register_group(database_configuration_group) - CONF.register_opts(get_database_configuration_opts(), group="database_configuration") - - orchestrator_group = cfg.OptGroup(name='orchestrator', - title='Orchestrator options') - CONF.register_group(orchestrator_group) - CONF.register_opts(get_orchestrator_opts(), group="orchestrator") - - secrouter_group = cfg.OptGroup(name='security_router', - title='Security Router options') - CONF.register_group(secrouter_group) - CONF.register_opts(get_security_router_opts(), group="security_router") - - manager_group = cfg.OptGroup(name='security_manager', - title='Manager options') - CONF.register_group(manager_group) - CONF.register_opts(get_manager_opts(), group="security_manager") - - secpolicy_group = cfg.OptGroup(name='security_policy', - title='Security policy options') - CONF.register_group(secpolicy_group) - CONF.register_opts(get_security_policy_opts(), group="security_policy") - - secfunction_group = cfg.OptGroup(name='security_function', - title='Security function options') - CONF.register_group(secfunction_group) - CONF.register_opts(get_security_function_opts(), group="security_function") - - interface_group = cfg.OptGroup(name='interface', - title='Interface options') - CONF.register_group(interface_group) - CONF.register_opts(get_interface_opts(), group="interface") - - keystone_group = cfg.OptGroup(name='keystone', - title='Keystone options') - CONF.register_group(keystone_group) - CONF.register_opts(get_keystone_opts(), group="keystone") - - filename = "moon.conf" - for _filename in ( - "/etc/moon/{}", - "conf/{}", - "../conf/{}", - ): - try: - default_config_files = (_filename.format(filename), ) - CONF(args=sys.argv[1:], - project=domain, - # version=pbr.version.VersionInfo('keystone').version_string(), - version=version, - usage=usage, - default_config_files=default_config_files) - except cfg.ConfigFilesNotFoundError: - continue - else: - LOG.info("Using {} configuration file".format(_filename.format(filename))) - return _filename.format(filename) - - -def get_opts(): - return [ - cfg.StrOpt('proxy', - default="", - help='Proxy server to use'), - cfg.StrOpt('dist_dir', - default="", - help='Directory where the python packages can be found'), - cfg.StrOpt('plugin_dir', - default="", - help='Directory where the python plugins can be found'), - cfg.StrOpt('docker_url', - default="unix://var/run/docker.sock", - help='Docker URL to connect to.'), - cfg.StrOpt('policy_directory', - default="/etc/moon/policies", - help='Directory containing all the intra-extension templates'), - cfg.StrOpt('root_policy_directory', - default="/etc/moon/policies/policy_root", - help='Directory containing the Root intra-extension template'), - cfg.StrOpt('master', - default="", - help='URL of the Moon Master'), - cfg.StrOpt('master_login', - default="", - help='Login to log into the Moon Master'), - cfg.StrOpt('master_password', - default="", - help='Password for the Moon Master'), - ] - - -# def get_messenger_opts(): -# return [ -# cfg.StrOpt('host', -# default="0.0.0.0", -# help='RabbitMQ server name or IP.'), -# cfg.IntOpt('port', -# default=8800, -# help='RabbitMQ server port.'), -# ] - - -def get_orchestrator_opts(): - return [ - cfg.StrOpt('host', - default="127.0.0.1", - help='Host binding'), - cfg.IntOpt('port', - default=38000, - help='Port number of the server'), - ] - - -def get_slave_opts(): - return [ - cfg.StrOpt('slave_name', - default="", - help='name of the slave'), - cfg.StrOpt('master_url', - default="", - help='URL of the RabbitMQ bus of the Master, ' - 'example: master_url=rabbit://moon:p4sswOrd1@messenger:5672/moon'), - cfg.StrOpt('master_login', - default="", - help='login name of the master administrator, example: master_login=admin'), - cfg.StrOpt('master_password', - default="", - help='password of the master administrator, example: master_password=XXXXXXX'), - ] - - -def get_security_router_opts(): - return [ - cfg.StrOpt('container', - default="", - help='Name of the container to download (if empty build from scratch)'), - cfg.StrOpt('host', - default="127.0.0.1", - help='Host binding'), - cfg.IntOpt('port', - default=38001, - help='Port number of the server'), - ] - - -def get_manager_opts(): - return [ - cfg.StrOpt('container', - default="", - help='Name of the container to download (if empty build from scratch)'), - cfg.StrOpt('host', - default="127.0.0.1", - help='Host binding'), - cfg.IntOpt('port', - default=38001, - help='Port number of the server'), - ] - - -def get_security_policy_opts(): - return [ - cfg.StrOpt('container', - default="", - help='Name of the container to download (if empty build from scratch)'), - ] - - -def get_security_function_opts(): - return [ - cfg.StrOpt('container', - default="", - help='Name of the container to download (if empty build from scratch)'), - ] - - -def get_interface_opts(): - return [ - cfg.StrOpt('container', - default="", - help='Name of the container to download (if empty build from scratch)'), - cfg.StrOpt('host', - default="127.0.0.1", - help='Host binding'), - cfg.IntOpt('port', - default=38002, - help='Port number of the server'), - ] - - -def get_database_opts(): - return [ - cfg.StrOpt('url', - default="mysql+pymysql://moonuser:password@localhost/moon", - help='URL of the database'), - cfg.StrOpt('driver', - default="sql", - help='Driver binding'), - ] - - -def get_database_configuration_opts(): - return [ - cfg.StrOpt('url', - default="", - help='URL of the database'), - cfg.StrOpt('driver', - default="memory", - help='Driver binding'), - ] - - -def get_keystone_opts(): - return [ - cfg.StrOpt('url', - default="http://localhost:35357", - help='URL of the Keystone manager.'), - cfg.StrOpt('user', - default="admin", - help='Username of the Keystone manager.'), - cfg.StrOpt('password', - default="nomoresecrete", - help='Password of the Keystone manager.'), - cfg.StrOpt('project', - default="admin", - help='Project used to connect to the Keystone manager.'), - cfg.StrOpt('domain', - default="Default", - help='Default domain for the Keystone manager.'), - cfg.StrOpt('check_token', - default="true", - help='If true, yes or strict, always check Keystone tokens against the server'), - cfg.StrOpt('server_crt', - default="", - help='If using Keystone in HTTPS mode, give a certificate filename here'), - ] - -filename = configure() - - -def get_docker_template_dir(templatename="template.dockerfile"): - path = os.path.dirname(os.path.abspath(filename)) - PATHS = ( - path, - os.path.join(path, "dockers"), - "/etc/moon/" - "~/.moon/" - ) - for _path in PATHS: - if os.path.isfile(os.path.join(_path, templatename)): - return _path - raise Exception("Configuration error, cannot find docker template in {}".format(PATHS)) - diff --git a/moonv4/moon_utilities/moon_utilities/security_functions.py b/moonv4/moon_utilities/moon_utilities/security_functions.py index ad1a44fa..50ab4daf 100644 --- a/moonv4/moon_utilities/moon_utilities/security_functions.py +++ b/moonv4/moon_utilities/moon_utilities/security_functions.py @@ -12,28 +12,14 @@ import requests import time from functools import wraps from flask import request -from oslo_log import log as logging -from oslo_config import cfg -import oslo_messaging +import logging from moon_utilities import exceptions from moon_utilities import configuration LOG = logging.getLogger("moon.utilities." + __name__) -CONF = cfg.CONF keystone_config = configuration.get_configuration("openstack/keystone")["openstack/keystone"] -slave = configuration.get_configuration(configuration.SLAVE)["slave"] - -__transport_master = oslo_messaging.get_transport(cfg.CONF, slave.get("master_url")) -__transport = oslo_messaging.get_transport(CONF) - -__n_transport = oslo_messaging.get_notification_transport(CONF) -__n_notifier = oslo_messaging.Notifier(__n_transport, - 'router.host', - driver='messagingv2', - topics=['authz-workers']) -__n_notifier = __n_notifier.prepare(publisher_id='router') - +TOKENS = {} __targets = {} @@ -111,6 +97,7 @@ def enforce(action_names, object_name, **extra): def login(user=None, password=None, domain=None, project=None, url=None): + start_time = time.time() if not user: user = keystone_config['user'] if not password: @@ -151,15 +138,19 @@ def login(user=None, password=None, domain=None, project=None, url=None): } } - req = requests.post("{}/auth/tokens".format(url), - json=data_auth, headers=headers, - verify=keystone_config['certificate']) - - if req.status_code in (200, 201, 204): - headers['X-Auth-Token'] = req.headers['X-Subject-Token'] - return headers - LOG.error(req.text) - raise exceptions.KeystoneError + while True: + req = requests.post("{}/auth/tokens".format(url), + json=data_auth, headers=headers, + verify=keystone_config['certificate']) + + if req.status_code in (200, 201, 204): + headers['X-Auth-Token'] = req.headers['X-Subject-Token'] + return headers + LOG.warning("Waiting for Keystone...") + if time.time() - start_time == 100: + LOG.error(req.text) + raise exceptions.KeystoneError + time.sleep(5) def logout(headers, url=None): @@ -173,95 +164,92 @@ def logout(headers, url=None): raise exceptions.KeystoneError -def notify(request_id, container_id, payload, event_type="authz"): - ctxt = { - 'request_id': request_id, - 'container_id': container_id - } - __n_notifier.critical(ctxt, event_type, payload=payload) - # FIXME (asteroide): the notification mus be done 2 times otherwise the notification - # may not be sent (need to search why) - __n_notifier.critical(ctxt, event_type, payload=payload) - - -def call(endpoint="security_router", ctx=None, method="route", **kwargs): - if not ctx: - ctx = dict() - if endpoint not in __targets: - __targets[endpoint] = dict() - __targets[endpoint]["endpoint"] = oslo_messaging.Target(topic=endpoint, version='1.0') - __targets[endpoint]["client"] = dict() - __targets[endpoint]["client"]["internal"] = oslo_messaging.RPCClient(__transport, - __targets[endpoint]["endpoint"]) - __targets[endpoint]["client"]["external"] = oslo_messaging.RPCClient(__transport_master, - __targets[endpoint]["endpoint"]) - if 'call_master' in ctx and ctx['call_master'] and slave.get("master_url"): - client = __targets[endpoint]["client"]["external"] - LOG.info("Calling master {} on {}...".format(method, endpoint)) - else: - client = __targets[endpoint]["client"]["internal"] - LOG.info("Calling {} on {}...".format(method, endpoint)) - result = copy.deepcopy(client.call(ctx, method, **kwargs)) - LOG.info("result={}".format(result)) - del client - return result - - class Context: - def __init__(self, _keystone_project_id, _subject, _object, _action, _request_id): - from moon_db.core import PDPManager, ModelManager, PolicyManager - self.PolicyManager = PolicyManager - self.ModelManager = ModelManager - self.PDPManager = PDPManager - self.__keystone_project_id = _keystone_project_id + def __init__(self, init_context, cache): + self.cache = cache + self.__keystone_project_id = init_context.get("project_id") self.__pdp_id = None self.__pdp_value = None - for _pdp_key, _pdp_value in PDPManager.get_pdp("admin").items(): - if _pdp_value["keystone_project_id"] == _keystone_project_id: + for _pdp_key, _pdp_value in self.cache.pdp.items(): + if _pdp_value["keystone_project_id"] == self.__keystone_project_id: self.__pdp_id = _pdp_key self.__pdp_value = copy.deepcopy(_pdp_value) break - self.__subject = _subject - self.__object = _object - self.__action = _action + if not self.__pdp_value: + raise exceptions.AuthzException( + "Cannot create context for authz " + "with Keystone project ID {}".format( + self.__keystone_project_id + )) + self.__subject = init_context.get("subject_name") + self.__object = init_context.get("object_name") + self.__action = init_context.get("action_name") self.__current_request = None - self.__request_id = _request_id - self.__index = 0 - self.__init_initial_request() + self.__request_id = init_context.get("req_id") + self.__cookie = init_context.get("cookie") + self.__manager_url = init_context.get("manager_url") + self.__interface_name = init_context.get("interface_name") + self.__index = -1 + # self.__init_initial_request() self.__headers = [] - policies = PolicyManager.get_policies("admin") - models = ModelManager.get_models("admin") + policies = self.cache.policies + models = self.cache.models for policy_id in self.__pdp_value["security_pipeline"]: model_id = policies[policy_id]["model_id"] for meta_rule in models[model_id]["meta_rules"]: self.__headers.append(meta_rule) - self.__meta_rules = ModelManager.get_meta_rules("admin") + self.__meta_rules = self.cache.meta_rules self.__pdp_set = {} + # self.__init_pdp_set() + + def delete_cache(self): + self.cache = {} + + def set_cache(self, cache): + self.cache = cache + + def increment_index(self): + self.__index += 1 + self.__init_current_request() self.__init_pdp_set() - def __init_initial_request(self): - subjects = self.PolicyManager.get_subjects("admin", policy_id=None) - for _subject_id, _subject_dict in subjects.items(): - if _subject_dict["name"] == self.__subject: - self.__subject = _subject_id - break - else: - raise exceptions.SubjectUnknown("Cannot find subject {}".format(self.__subject)) - objects = self.PolicyManager.get_objects("admin", policy_id=None) - for _object_id, _object_dict in objects.items(): - if _object_dict["name"] == self.__object: - self.__object = _object_id - break - else: - raise exceptions.ObjectUnknown("Cannot find object {}".format(self.__object)) - actions = self.PolicyManager.get_actions("admin", policy_id=None) - for _action_id, _action_dict in actions.items(): - if _action_dict["name"] == self.__action: - self.__action = _action_id - break - else: - raise exceptions.ActionUnknown("Cannot find action {}".format(self.__action)) + @property + def current_state(self): + return self.__pdp_set[self.__headers[self.__index]]['effect'] + + @current_state.setter + def current_state(self, state): + if state not in ("grant", "deny", "passed"): + state = "passed" + self.__pdp_set[self.__headers[self.__index]]['effect'] = state + + @current_state.deleter + def current_state(self): + self.__pdp_set[self.__headers[self.__index]]['effect'] = "unset" + + @property + def current_policy_id(self): + return self.__pdp_value["security_pipeline"][self.__index] + + @current_policy_id.setter + def current_policy_id(self, value): + pass + + @current_policy_id.deleter + def current_policy_id(self): + pass + + def __init_current_request(self): + self.__subject = self.cache.get_subject( + self.__pdp_value["security_pipeline"][self.__index], + self.__subject) + self.__object = self.cache.get_object( + self.__pdp_value["security_pipeline"][self.__index], + self.__object) + self.__action = self.cache.get_action( + self.__pdp_value["security_pipeline"][self.__index], + self.__action) self.__current_request = dict(self.initial_request) def __init_pdp_set(self): @@ -269,67 +257,70 @@ class Context: self.__pdp_set[header] = dict() self.__pdp_set[header]["meta_rules"] = self.__meta_rules[header] self.__pdp_set[header]["target"] = self.__add_target(header) - # TODO (asteroide): the following information must be retrieve somewhere self.__pdp_set[header]["effect"] = "unset" self.__pdp_set["effect"] = "deny" - @staticmethod - def update_target(context): - from moon_db.core import PDPManager, ModelManager, PolicyManager - # result = dict() - current_request = context['current_request'] - _subject = current_request.get("subject") - _object = current_request.get("object") - _action = current_request.get("action") - meta_rule_id = context['headers'][context['index']] - policy_id = PolicyManager.get_policy_from_meta_rules("admin", meta_rule_id) - meta_rules = ModelManager.get_meta_rules("admin") - # for meta_rule_id in meta_rules: - for sub_cat in meta_rules[meta_rule_id]['subject_categories']: - if sub_cat not in context["pdp_set"][meta_rule_id]["target"]: - context["pdp_set"][meta_rule_id]["target"][sub_cat] = [] - for assign in PolicyManager.get_subject_assignments("admin", policy_id, _subject, sub_cat).values(): - for assign in assign["assignments"]: - if assign not in context["pdp_set"][meta_rule_id]["target"][sub_cat]: - context["pdp_set"][meta_rule_id]["target"][sub_cat].append(assign) - for obj_cat in meta_rules[meta_rule_id]['object_categories']: - if obj_cat not in context["pdp_set"][meta_rule_id]["target"]: - context["pdp_set"][meta_rule_id]["target"][obj_cat] = [] - for assign in PolicyManager.get_object_assignments("admin", policy_id, _object, obj_cat).values(): - for assign in assign["assignments"]: - if assign not in context["pdp_set"][meta_rule_id]["target"][obj_cat]: - context["pdp_set"][meta_rule_id]["target"][obj_cat].append(assign) - for act_cat in meta_rules[meta_rule_id]['action_categories']: - if act_cat not in context["pdp_set"][meta_rule_id]["target"]: - context["pdp_set"][meta_rule_id]["target"][act_cat] = [] - for assign in PolicyManager.get_action_assignments("admin", policy_id, _action, act_cat).values(): - for assign in assign["assignments"]: - if assign not in context["pdp_set"][meta_rule_id]["target"][act_cat]: - context["pdp_set"][meta_rule_id]["target"][act_cat].append(assign) - # context["pdp_set"][meta_rule_id]["target"].update(result) + # def update_target(self, context): + # # result = dict() + # current_request = context['current_request'] + # _subject = current_request.get("subject") + # _object = current_request.get("object") + # _action = current_request.get("action") + # meta_rule_id = context['headers'][context['index']] + # policy_id = self.cache.get_policy_from_meta_rules(meta_rule_id) + # meta_rules = self.cache.meta_rules() + # # for meta_rule_id in meta_rules: + # for sub_cat in meta_rules[meta_rule_id]['subject_categories']: + # if sub_cat not in context["pdp_set"][meta_rule_id]["target"]: + # context["pdp_set"][meta_rule_id]["target"][sub_cat] = [] + # for assign in self.cache.get_subject_assignments(policy_id, _subject, sub_cat).values(): + # for assign in assign["assignments"]: + # if assign not in context["pdp_set"][meta_rule_id]["target"][sub_cat]: + # context["pdp_set"][meta_rule_id]["target"][sub_cat].append(assign) + # for obj_cat in meta_rules[meta_rule_id]['object_categories']: + # if obj_cat not in context["pdp_set"][meta_rule_id]["target"]: + # context["pdp_set"][meta_rule_id]["target"][obj_cat] = [] + # for assign in self.cache.get_object_assignments(policy_id, _object, obj_cat).values(): + # for assign in assign["assignments"]: + # if assign not in context["pdp_set"][meta_rule_id]["target"][obj_cat]: + # context["pdp_set"][meta_rule_id]["target"][obj_cat].append(assign) + # for act_cat in meta_rules[meta_rule_id]['action_categories']: + # if act_cat not in context["pdp_set"][meta_rule_id]["target"]: + # context["pdp_set"][meta_rule_id]["target"][act_cat] = [] + # for assign in self.cache.get_action_assignments(policy_id, _action, act_cat).values(): + # for assign in assign["assignments"]: + # if assign not in context["pdp_set"][meta_rule_id]["target"][act_cat]: + # context["pdp_set"][meta_rule_id]["target"][act_cat].append(assign) + # # context["pdp_set"][meta_rule_id]["target"].update(result) def __add_target(self, meta_rule_id): + """build target from meta_rule + + Target is dict of categories as keys ; and the value of each category + will be a list of assignments + + """ result = dict() _subject = self.__current_request["subject"] _object = self.__current_request["object"] _action = self.__current_request["action"] - meta_rules = self.ModelManager.get_meta_rules("admin") - policy_id = self.PolicyManager.get_policy_from_meta_rules("admin", meta_rule_id) + meta_rules = self.cache.meta_rules + policy_id = self.cache.get_policy_from_meta_rules(meta_rule_id) for sub_cat in meta_rules[meta_rule_id]['subject_categories']: if sub_cat not in result: result[sub_cat] = [] - for assign in self.PolicyManager.get_subject_assignments("admin", policy_id, _subject, sub_cat).values(): - result[sub_cat].extend(assign["assignments"]) + result[sub_cat].extend( + self.cache.get_subject_assignments(policy_id, _subject, sub_cat)) for obj_cat in meta_rules[meta_rule_id]['object_categories']: if obj_cat not in result: result[obj_cat] = [] - for assign in self.PolicyManager.get_object_assignments("admin", policy_id, _object, obj_cat).values(): - result[obj_cat].extend(assign["assignments"]) + result[obj_cat].extend( + self.cache.get_object_assignments(policy_id, _object, obj_cat)) for act_cat in meta_rules[meta_rule_id]['action_categories']: if act_cat not in result: result[act_cat] = [] - for assign in self.PolicyManager.get_action_assignments("admin", policy_id, _action, act_cat).values(): - result[act_cat].extend(assign["assignments"]) + result[act_cat].extend( + self.cache.get_action_assignments(policy_id, _action, act_cat)) return result def __repr__(self): @@ -356,6 +347,8 @@ pdp_set: {pdp_set} "index": copy.deepcopy(self.__index), "pdp_set": copy.deepcopy(self.__pdp_set), "request_id": copy.deepcopy(self.__request_id), + "manager_url": copy.deepcopy(self.__manager_url), + "interface_name": copy.deepcopy(self.__interface_name), } @property @@ -371,6 +364,42 @@ pdp_set: {pdp_set} raise Exception("You cannot update the request_id") @property + def manager_url(self): + return self.__manager_url + + @manager_url.setter + def manager_url(self, value): + raise Exception("You cannot update the manager_url") + + @manager_url.deleter + def manager_url(self): + raise Exception("You cannot update the manager_url") + + @property + def interface_name(self): + return self.__interface_name + + @interface_name.setter + def interface_name(self, value): + raise Exception("You cannot update the interface_name") + + @interface_name.deleter + def interface_name(self): + raise Exception("You cannot update the interface_name") + + @property + def cookie(self): + return self.__cookie + + @cookie.setter + def cookie(self, value): + raise Exception("You cannot update the cookie") + + @cookie.deleter + def cookie(self): + raise Exception("You cannot delete the cookie") + + @property def initial_request(self): return { "subject": self.__subject, @@ -395,7 +424,8 @@ pdp_set: {pdp_set} @current_request.setter def current_request(self, value): self.__current_request = copy.deepcopy(value) - # Note (asteroide): if the current request is modified, we must update the PDP Set. + # Note (asteroide): if the current request is modified, + # we must update the PDP Set. self.__init_pdp_set() @current_request.deleter @@ -425,7 +455,7 @@ pdp_set: {pdp_set} @index.deleter def index(self): - self.__index = 0 + self.__index = -1 @property def pdp_set(self): @@ -439,8 +469,6 @@ pdp_set: {pdp_set} def pdp_set(self): self.__pdp_set = {} -TOKENS = {} - def check_token(token, url=None): _verify = False diff --git a/moonv4/moon_utilities/requirements.txt b/moonv4/moon_utilities/requirements.txt index e30f5d29..5b80e5f2 100644 --- a/moonv4/moon_utilities/requirements.txt +++ b/moonv4/moon_utilities/requirements.txt @@ -1,8 +1,3 @@ -kombu !=4.0.1,!=4.0.0 -oslo.messaging -oslo.config -oslo.log -vine werkzeug flask requests
\ No newline at end of file diff --git a/moonv4/moon_utilities/setup.py b/moonv4/moon_utilities/setup.py index 6c9ffd3d..21e11419 100644 --- a/moonv4/moon_utilities/setup.py +++ b/moonv4/moon_utilities/setup.py @@ -17,13 +17,13 @@ setup( packages=find_packages(), - author="Thomas Duval", + author='Thomas Duval', - author_email="thomas.duval@orange.com", + author_email='thomas.duval@orange.com', - description="Some utilities for all the Moon components", + description='Some utilities for all the Moon components', - long_description=open('README.rst').read(), + long_description=open('README.md').read(), install_requires=required, @@ -32,12 +32,11 @@ setup( url='https://git.opnfv.org/cgit/moon', classifiers=[ - "Programming Language :: Python", - "Development Status :: 1 - Planning", - "License :: OSI Approved", - "Natural Language :: French", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3", + 'Programming Language :: Python :: 3', + 'Development Status :: 1 - Planning', + 'License :: OSI Approved', + 'Natural Language :: English', + 'Operating System :: OS Independent', ], ) diff --git a/moonv4/moon_utilities/tests/unit_python/conftest.py b/moonv4/moon_utilities/tests/unit_python/conftest.py new file mode 100644 index 00000000..7217586a --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/conftest.py @@ -0,0 +1,17 @@ +import pytest +import requests_mock +import mock_components +import mock_keystone +import mock_cache + + +@pytest.fixture(autouse=True) +def no_requests(monkeypatch): + """ Modify the response from Requests module + """ + with requests_mock.Mocker(real_http=True) as m: + mock_components.register_components(m) + mock_keystone.register_keystone(m) + mock_cache.register_cache(m) + print("End registering URI") + yield m
\ No newline at end of file diff --git a/moonv4/moon_utilities/tests/unit_python/mock_cache.py b/moonv4/moon_utilities/tests/unit_python/mock_cache.py new file mode 100644 index 00000000..b2b287a9 --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/mock_cache.py @@ -0,0 +1,321 @@ +from utilities import CONF + +pdp_mock = { + "pdp_id1": { + "name": "...", + "security_pipeline": ["policy_id_1", "policy_id_2"], + "keystone_project_id": "keystone_project_id1", + "description": "...", + }, + "pdp_id12": { + "name": "...", + "security_pipeline": ["policy_id_1", "policy_id_2"], + "keystone_project_id": "keystone_project_id1", + "description": "...", + } +} + +meta_rules_mock = { + "meta_rule_id1": { + "name": "meta_rule1", + "algorithm": "name of the meta rule algorithm", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + }, + "meta_rule_id2": { + "name": "name of the meta rules2", + "algorithm": "name of the meta rule algorithm", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + } +} + +policies_mock = { + "policy_id_1": { + "name": "test_policy1", + "model_id": "model_id_1", + "genre": "authz", + "description": "test", + }, + "policy_id_2": { + "name": "test_policy2", + "model_id": "model_id_2", + "genre": "authz", + "description": "test", + } +} + +subject_mock = { + "policy_id_1": { + "subject_id": { + "name": "subject_name", + "keystone_id": "keystone_project_id1", + "description": "a description" + } + }, + "policy_id_2": { + "subject_id": { + "name": "subject_name", + "keystone_id": "keystone_project_id1", + "description": "a description" + } + } +} + +subject_assignment_mock = { + "subject_id": { + "policy_id": "ID of the policy", + "subject_id": "ID of the subject", + "category_id": "ID of the category", + "assignments": [], + } +} + +object_mock = { + "policy_id_1": { + "object_id": { + "name": "object_name", + "description": "a description" + } + }, + "policy_id_2": { + "object_id": { + "name": "object_name", + "description": "a description" + } + } +} + +object_assignment_mock = { + "object_id": { + "policy_id": "ID of the policy", + "object_id": "ID of the object", + "category_id": "ID of the category", + "assignments": [], + } +} + +action_mock = { + "policy_id_1": { + "action_id": { + "name": "action_name", + "description": "a description" + } + }, + "policy_id_2": { + "action_id": { + "name": "action_name", + "description": "a description" + } + } +} + +action_assignment_mock = { + "action_id": { + "policy_id": "ID of the policy", + "action_id": "ID of the action", + "category_id": "ID of the category", + "assignments": [], + } +} + +models_mock = { + "model_id_1": { + "name": "test_model", + "description": "test", + "meta_rules": ["meta_rule_id1"] + }, + "model_id_2": { + "name": "test_model", + "description": "test", + "meta_rules": ["meta_rule_id2"] + }, +} + +rules_mock = { + "rules": { + "meta_rule_id": "meta_rule_id1", + "rule_id1": { + "rule": ["subject_data_id1", + "object_data_id1", + "action_data_id1"], + "instructions": ( + {"decision": "grant"}, + # "grant" to immediately exit, + # "continue" to wait for the result of next policy + # "deny" to deny the request + ) + }, + "rule_id2": { + "rule": ["subject_data_id2", + "object_data_id2", + "action_data_id2"], + "instructions": ( + { + "update": { + "operation": "add", + # operations may be "add" or "delete" + "target": "rbac:role:admin" + # add the role admin to the current user + } + }, + {"chain": {"name": "rbac"}} + # chain with the policy named rbac + ) + } + } +} + + +def register_cache(m): + """ Modify the response from Requests module + """ + register_pdp(m) + register_meta_rules(m) + register_policies(m) + register_models(m) + register_policy_subject(m, "policy_id_1") + register_policy_subject(m, "policy_id_2") + register_policy_object(m, "policy_id_1") + register_policy_object(m, "policy_id_2") + register_policy_action(m, "policy_id_1") + register_policy_action(m, "policy_id_2") + register_policy_subject_assignment(m, "policy_id_1", "subject_id") + # register_policy_subject_assignment_list(m1, "policy_id_1") + register_policy_subject_assignment(m, "policy_id_2", "subject_id") + # register_policy_subject_assignment_list(m1, "policy_id_2") + register_policy_object_assignment(m, "policy_id_1", "object_id") + # register_policy_object_assignment_list(m1, "policy_id_1") + register_policy_object_assignment(m, "policy_id_2", "object_id") + # register_policy_object_assignment_list(m1, "policy_id_2") + register_policy_action_assignment(m, "policy_id_1", "action_id") + # register_policy_action_assignment_list(m1, "policy_id_1") + register_policy_action_assignment(m, "policy_id_2", "action_id") + # register_policy_action_assignment_list(m1, "policy_id_2") + register_rules(m, "policy_id1") + + +def register_pdp(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'pdp'), + json={'pdps': pdp_mock} + ) + + +def register_meta_rules(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'meta_rules'), + json={'meta_rules': meta_rules_mock} + ) + + +def register_policies(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies'), + json={'policies': policies_mock} + ) + + +def register_models(m): + m.register_uri( + 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'models'), + json={'models': models_mock} + ) + + +def register_policy_subject(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/subjects'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', policy_id), + json={'subjects': subject_mock[policy_id]} + ) + + +def register_policy_object(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/objects'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', policy_id), + json={'objects': object_mock[policy_id]} + ) + + +def register_policy_action(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/actions'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', policy_id), + json={'actions': action_mock[policy_id]} + ) + + +def register_policy_subject_assignment(m, policy_id, subj_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/subject_assignments/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, + subj_id), + json={'subject_assignments': subject_assignment_mock} + ) + + +def register_policy_subject_assignment_list(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/subject_assignments'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id), + json={'subject_assignments': subject_assignment_mock} + ) + + +def register_policy_object_assignment(m, policy_id, obj_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/object_assignments/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, + obj_id), + json={'object_assignments': object_assignment_mock} + ) + + +def register_policy_object_assignment_list(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/object_assignments'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id), + json={'object_assignments': object_assignment_mock} + ) + + +def register_policy_action_assignment(m, policy_id, action_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/action_assignments/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, + action_id), + json={'action_assignments': action_assignment_mock} + ) + + +def register_policy_action_assignment_list(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/action_assignments'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id), + json={'action_assignments': action_assignment_mock} + ) + + +def register_rules(m, policy_id): + m.register_uri( + 'GET', 'http://{}:{}/{}/{}/{}'.format(CONF['components']['manager']['hostname'], + CONF['components']['manager']['port'], 'policies', + policy_id, 'rules'), + json={'rules': rules_mock} + )
\ No newline at end of file diff --git a/moonv4/moon_utilities/tests/unit_python/mock_components.py b/moonv4/moon_utilities/tests/unit_python/mock_components.py new file mode 100644 index 00000000..a0319e1a --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/mock_components.py @@ -0,0 +1,27 @@ +import utilities + +COMPONENTS = ( + "logging", + "openstack/keystone", + "database", + "slave", + "components/manager", + "components/orchestrator", + "components/interface", +) + + +def register_components(m): + for component in COMPONENTS: + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/{}'.format(component), + json=[{'Key': component, 'Value': utilities.get_b64_conf(component)}] + ) + + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/components?recurse=true', + json=[ + {"Key": key, "Value": utilities.get_b64_conf(key)} for key in COMPONENTS + ], + # json={'Key': "components", 'Value': get_b64_conf("components")} + )
\ No newline at end of file diff --git a/moonv4/moon_utilities/tests/unit_python/mock_keystone.py b/moonv4/moon_utilities/tests/unit_python/mock_keystone.py new file mode 100644 index 00000000..c0b26b88 --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/mock_keystone.py @@ -0,0 +1,23 @@ +def register_keystone(m): + m.register_uri( + 'POST', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'DELETE', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users/', + json={"users": [{ + "id": "1111111111111" + }]} + )
\ No newline at end of file diff --git a/moonv4/moon_utilities/tests/unit_python/requirements.txt b/moonv4/moon_utilities/tests/unit_python/requirements.txt new file mode 100644 index 00000000..3c1ad607 --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/requirements.txt @@ -0,0 +1,2 @@ +pytest +requests_mock
\ No newline at end of file diff --git a/moonv4/moon_utilities/tests/unit_python/test_cache.py b/moonv4/moon_utilities/tests/unit_python/test_cache.py new file mode 100644 index 00000000..3d4f7292 --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/test_cache.py @@ -0,0 +1,75 @@ +import pytest + + +def test_authz_request(): + from moon_utilities import cache + c = cache.Cache() + assert isinstance(c.authz_requests, dict) + + +def test_get_subject_success(): + from moon_utilities import cache + cache_obj = cache.Cache() + policy_id = 'policy_id_1' + name = 'subject_name' + subject_id = cache_obj.get_subject(policy_id, name) + assert subject_id is not None + + +def test_get_subject_failure(): + from moon_utilities import cache + cache_obj = cache.Cache() + policy_id = 'policy_id_1' + name = 'invalid name' + with pytest.raises(Exception) as exception_info: + cache_obj.get_subject(policy_id, name) + assert str(exception_info.value) == '400: Subject Unknown' + + +def test_get_object_success(): + from moon_utilities import cache + cache_obj = cache.Cache() + policy_id = 'policy_id_1' + name = 'object_name' + object_id = cache_obj.get_object(policy_id, name) + assert object_id is not None + + +def test_get_object_failure(): + from moon_utilities import cache + cache_obj = cache.Cache() + policy_id = 'policy_id_1' + name = 'invalid name' + with pytest.raises(Exception) as exception_info: + cache_obj.get_object(policy_id, name) + assert str(exception_info.value) == '400: Subject Unknown' + + +def test_get_action_success(): + from moon_utilities import cache + cache_obj = cache.Cache() + policy_id = 'policy_id_1' + name = 'action_name' + action_id = cache_obj.get_action(policy_id, name) + assert action_id is not None + + +def test_get_action_failure(): + from moon_utilities import cache + cache_obj = cache.Cache() + policy_id = 'policy_id_1' + name = 'invalid name' + with pytest.raises(Exception) as exception_info: + cache_obj.get_action(policy_id, name) + assert str(exception_info.value) == '400: Subject Unknown' + + +def test_cache_manager(): + from moon_utilities import cache + cache_obj = cache.Cache() + assert cache_obj.pdp is not None + assert cache_obj.meta_rules is not None + assert len(cache_obj.meta_rules) == 2 + assert cache_obj.policies is not None + assert len(cache_obj.policies) == 2 + assert cache_obj.models is not None
\ No newline at end of file diff --git a/moonv4/moon_utilities/tests/unit_python/test_configuration.py b/moonv4/moon_utilities/tests/unit_python/test_configuration.py new file mode 100644 index 00000000..0ebff995 --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/test_configuration.py @@ -0,0 +1,5 @@ + +def test_get_components(): + from moon_utilities import configuration + assert isinstance(configuration.get_components(), dict) + diff --git a/moonv4/moon_utilities/tests/unit_python/utilities.py b/moonv4/moon_utilities/tests/unit_python/utilities.py new file mode 100644 index 00000000..1d79d890 --- /dev/null +++ b/moonv4/moon_utilities/tests/unit_python/utilities.py @@ -0,0 +1,136 @@ +import base64 +import json + + +CONF = { + "openstack": { + "keystone": { + "url": "http://keystone:5000/v3", + "user": "admin", + "check_token": False, + "password": "p4ssw0rd", + "domain": "default", + "certificate": False, + "project": "admin" + } + }, + "components": { + "wrapper": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_wrapper:v4.3", + "timeout": 5, + "hostname": "wrapper" + }, + "manager": { + "bind": "0.0.0.0", + "port": 8082, + "container": "wukongsun/moon_manager:v4.3", + "hostname": "manager" + }, + "port_start": 31001, + "orchestrator": { + "bind": "0.0.0.0", + "port": 8083, + "container": "wukongsun/moon_orchestrator:v4.3", + "hostname": "interface" + }, + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + } + }, + "plugins": { + "session": { + "port": 8082, + "container": "asteroide/session:latest" + }, + "authz": { + "port": 8081, + "container": "wukongsun/moon_authz:v4.3" + } + }, + "logging": { + "handlers": { + "file": { + "filename": "/tmp/moon.log", + "class": "logging.handlers.RotatingFileHandler", + "level": "DEBUG", + "formatter": "custom", + "backupCount": 3, + "maxBytes": 1048576 + }, + "console": { + "class": "logging.StreamHandler", + "formatter": "brief", + "level": "INFO", + "stream": "ext://sys.stdout" + } + }, + "formatters": { + "brief": { + "format": "%(levelname)s %(name)s %(message)-30s" + }, + "custom": { + "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s" + } + }, + "root": { + "handlers": [ + "console" + ], + "level": "ERROR" + }, + "version": 1, + "loggers": { + "moon": { + "handlers": [ + "console", + "file" + ], + "propagate": False, + "level": "DEBUG" + } + } + }, + "slave": { + "name": None, + "master": { + "url": None, + "login": None, + "password": None + } + }, + "docker": { + "url": "tcp://172.88.88.1:2376", + "network": "moon" + }, + "database": { + "url": "sqlite:///database.db", + # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon", + "driver": "sql" + }, + "messenger": { + "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon" + } +} + + +def get_b64_conf(component=None): + if component == "components": + return base64.b64encode( + json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8') + elif component in CONF: + return base64.b64encode( + json.dumps( + CONF[component]).encode('utf-8')+b"\n").decode('utf-8') + elif not component: + return base64.b64encode( + json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8') + elif "/" in component: + key1, _, key2 = component.partition("/") + return base64.b64encode( + json.dumps( + CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8') |