From 1100c66ce03a059ebe7ece9734e799b49b3a5a9e Mon Sep 17 00:00:00 2001 From: WuKong Date: Sat, 23 Dec 2017 21:49:35 +0100 Subject: moonv4 cleanup Change-Id: Icef927f3236d985ac13ff7376f6ce6314b2b39b0 Signed-off-by: WuKong --- python_moondb/Changelog | 55 + python_moondb/LICENSE | 202 +++ python_moondb/MANIFEST.in | 10 + python_moondb/README.md | 32 + python_moondb/bin/drop_tables.sql | 18 + python_moondb/build.sh | 38 + python_moondb/python_moondb/__init__.py | 7 + python_moondb/python_moondb/api/__init__.py | 0 python_moondb/python_moondb/api/keystone.py | 106 ++ python_moondb/python_moondb/api/managers.py | 15 + python_moondb/python_moondb/api/model.py | 132 ++ python_moondb/python_moondb/api/pdp.py | 38 + python_moondb/python_moondb/api/policy.py | 248 +++ python_moondb/python_moondb/backends/__init__.py | 97 + python_moondb/python_moondb/backends/flat.py | 89 + python_moondb/python_moondb/backends/sql.py | 1875 ++++++++++++++++++++ python_moondb/python_moondb/core.py | 297 ++++ python_moondb/python_moondb/db_manager.py | 82 + .../python_moondb/migrate_repo/__init__.py | 0 .../migrate_repo/versions/001_moon.py | 216 +++ .../migrate_repo/versions/__init__.py | 0 python_moondb/requirements.txt | 6 + python_moondb/setup.py | 55 + python_moondb/tests/unit_python/conftest.py | 145 ++ python_moondb/tests/unit_python/mock_components.py | 27 + python_moondb/tests/unit_python/mock_keystone.py | 23 + python_moondb/tests/unit_python/requirements.txt | 5 + python_moondb/tests/unit_python/test_policies.py | 77 + python_moondb/tests/unit_python/utilities.py | 136 ++ 29 files changed, 4031 insertions(+) create mode 100644 python_moondb/Changelog create mode 100644 python_moondb/LICENSE create mode 100644 python_moondb/MANIFEST.in create mode 100644 python_moondb/README.md create mode 100644 python_moondb/bin/drop_tables.sql create mode 100644 python_moondb/build.sh create mode 100644 python_moondb/python_moondb/__init__.py create mode 100644 python_moondb/python_moondb/api/__init__.py create mode 100644 python_moondb/python_moondb/api/keystone.py create mode 100644 python_moondb/python_moondb/api/managers.py create mode 100644 python_moondb/python_moondb/api/model.py create mode 100644 python_moondb/python_moondb/api/pdp.py create mode 100644 python_moondb/python_moondb/api/policy.py create mode 100644 python_moondb/python_moondb/backends/__init__.py create mode 100644 python_moondb/python_moondb/backends/flat.py create mode 100644 python_moondb/python_moondb/backends/sql.py create mode 100644 python_moondb/python_moondb/core.py create mode 100644 python_moondb/python_moondb/db_manager.py create mode 100644 python_moondb/python_moondb/migrate_repo/__init__.py create mode 100644 python_moondb/python_moondb/migrate_repo/versions/001_moon.py create mode 100644 python_moondb/python_moondb/migrate_repo/versions/__init__.py create mode 100644 python_moondb/requirements.txt create mode 100644 python_moondb/setup.py create mode 100644 python_moondb/tests/unit_python/conftest.py create mode 100644 python_moondb/tests/unit_python/mock_components.py create mode 100644 python_moondb/tests/unit_python/mock_keystone.py create mode 100644 python_moondb/tests/unit_python/requirements.txt create mode 100644 python_moondb/tests/unit_python/test_policies.py create mode 100644 python_moondb/tests/unit_python/utilities.py (limited to 'python_moondb') diff --git a/python_moondb/Changelog b/python_moondb/Changelog new file mode 100644 index 00000000..ff244af5 --- /dev/null +++ b/python_moondb/Changelog @@ -0,0 +1,55 @@ +# 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'. + + +CHANGES +======= + +0.1.0 +----- +- First version of the moon_db library. + +1.0.0 +----- +- First public version of the moon_db library. + +1.0.1 +----- +- Update setup.py to force the installation of requirements. + +1.0.2 +----- +- Test PyPi upload + +1.0.3 +----- +- Fix a bug in core.py +- Update db_manager + +1.1.0 +----- +- When adding a subject, check the existence of that user in the Keystone DB and + create it if necessary + +1.2.0 +----- +- Update the db_manager in order to use it for tests + +1.2.1 +----- +- Update moon_db_manager in order to use it for unit tests + +1.2.2 +----- +- Fix a bug in moon_db_manager + +1.2.3 +----- +- Cleanup moon_db code + +1.2.4 +----- +- Update the name of the library (from moon_db) + diff --git a/python_moondb/LICENSE b/python_moondb/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/python_moondb/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + 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/python_moondb/MANIFEST.in b/python_moondb/MANIFEST.in new file mode 100644 index 00000000..82b40140 --- /dev/null +++ b/python_moondb/MANIFEST.in @@ -0,0 +1,10 @@ +# 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'. + +include README.rst +include LICENSE +include setup.py +include requirements.txt +graft bin \ No newline at end of file diff --git a/python_moondb/README.md b/python_moondb/README.md new file mode 100644 index 00000000..d36c6ae3 --- /dev/null +++ b/python_moondb/README.md @@ -0,0 +1,32 @@ +# python_moondb + +This package contains the database module for the Moon project +It is designed to provide a driver to access the Moon database. + +For any other information, refer to the parent project: + + https://git.opnfv.org/moon + +## Build +### Build Python Package +```bash +cd ${MOON_HOME}/python_moondb +python3 setup.py sdist bdist_wheel +``` + +### Push Python Package to PIP +```bash +cd ${MOON_HOME}/python_moondb +gpg --detach-sign -u "${GPG_ID}" -a dist/python_moondb-X.Y.Z-py3-none-any.whl +gpg --detach-sign -u "${GPG_ID}" -a dist/python_moondb-X.Y.Z.tar.gz +twine upload dist/python_moondb-X.Y.Z-py3-none-any.whl dist/python_moondb-X.Y.Z-py3-none-any.whl.asc +twine upload dist/python_moondb-X.Y.Z.tar.gz dist/python_moondb-X.Y.Z.tar.gz.asc +``` + +## Test +### Python Unit Test +launch Docker for Python unit tests +```bash +cd ${MOON_HOME}/python_moondb +docker run --rm --volume $(pwd):/data wukongsun/moon_python_unit_test:latest +``` \ No newline at end of file diff --git a/python_moondb/bin/drop_tables.sql b/python_moondb/bin/drop_tables.sql new file mode 100644 index 00000000..f5f65ea7 --- /dev/null +++ b/python_moondb/bin/drop_tables.sql @@ -0,0 +1,18 @@ +use moon; +drop table action_assignments; +drop table object_assignments; +drop table subject_assignments; +drop table subject_scopes; +drop table action_scopes; +drop table object_scopes; +drop table action_categories; +drop table subject_categories; +drop table object_categories; +drop table rules; +drop table sub_meta_rules; +drop table actions; +drop table objects; +drop table subjects; +drop table tenants; +drop table intra_extensions; +show tables; diff --git a/python_moondb/build.sh b/python_moondb/build.sh new file mode 100644 index 00000000..f109e9b8 --- /dev/null +++ b/python_moondb/build.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +VERSION=moon_db-$(grep __version__ moon_db/__init__.py | cut -d "\"" -f 2) + +python3 setup.py sdist bdist_wheel + +rm dist/*.asc 2>/dev/null + +gpg --detach-sign -u "A0A96E75" -a dist/${VERSION}-py3-none-any.whl +gpg --detach-sign -u "A0A96E75" -a dist/${VERSION}.tar.gz + +if [ "$1" = "upload" ]; then + twine upload dist/${VERSION}-py3-none-any.whl dist/${VERSION}-py3-none-any.whl.asc + twine upload dist/${VERSION}.tar.gz dist/${VERSION}.tar.gz.asc + rm -f ../moon_orchestrator/dist/moon_db* + rm -f ../moon_interface/dist/moon_db* + rm -f ../moon_manager/dist/moon_db* + rm -f ../moon_authz/dist/moon_db* + rm -f ../moon_wrapper/dist/moon_db* +fi + +if [ "$1" = "copy" ]; then + mkdir -p ../moon_orchestrator/dist/ 2>/dev/null + rm -f ../moon_orchestrator/dist/moon_db* + cp -v dist/${VERSION}-py3-none-any.whl ../moon_orchestrator/dist/ + mkdir -p ../moon_interface/dist/ 2>/dev/null + rm -f ../moon_interface/dist/moon_db* + cp -v dist/${VERSION}-py3-none-any.whl ../moon_interface/dist/ + mkdir -p ../moon_manager/dist/ 2>/dev/null + rm -f ../moon_manager/dist/moon_db* + cp -v dist/${VERSION}-py3-none-any.whl ../moon_manager/dist/ + mkdir -p ../moon_authz/dist/ 2>/dev/null + rm -f ../moon_authz/dist/moon_db* + cp -v dist/${VERSION}-py3-none-any.whl ../moon_authz/dist/ + mkdir -p ../moon_wrapper/dist/ 2>/dev/null + rm -f ../moon_wrapper/dist/moon_db* + cp -v dist/${VERSION}-py3-none-any.whl ../moon_wrapper/dist/ +fi diff --git a/python_moondb/python_moondb/__init__.py b/python_moondb/python_moondb/__init__.py new file mode 100644 index 00000000..73faf752 --- /dev/null +++ b/python_moondb/python_moondb/__init__.py @@ -0,0 +1,7 @@ +# 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'. + +__version__ = "1.2.4" + diff --git a/python_moondb/python_moondb/api/__init__.py b/python_moondb/python_moondb/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/python_moondb/python_moondb/api/keystone.py b/python_moondb/python_moondb/api/keystone.py new file mode 100644 index 00000000..f5410190 --- /dev/null +++ b/python_moondb/python_moondb/api/keystone.py @@ -0,0 +1,106 @@ +# 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 requests +import json +from uuid import uuid4 +from oslo_log import log as logging +from python_moonutilities import exceptions, configuration +from python_moonutilities.security_functions import filter_input, login, logout +from python_moondb.api.managers import Managers + +LOG = logging.getLogger("moon.db.api.keystone") + + +class KeystoneManager(Managers): + + def __init__(self, connector=None): + self.driver = connector.driver + Managers.KeystoneManager = self + conf = configuration.get_configuration("openstack/keystone")['openstack/keystone'] + + self.__url = conf['url'] + self.__user = conf['user'] + self.__password = conf['password'] + self.__domain = conf['domain'] + self.__project = conf['project'] + try: + os.environ.pop("http_proxy") + os.environ.pop("https_proxy") + except KeyError: + pass + + def __get(self, endpoint, _exception=exceptions.KeystoneError): + _headers = login() + req = requests.get("{}{}".format(self.__url, endpoint), headers=_headers, verify=False) + if req.status_code not in (200, 201): + LOG.error(req.text) + raise _exception + data = req.json() + logout(_headers) + return data + + def __post(self, endpoint, data=None, _exception=exceptions.KeystoneError): + _headers = login() + req = requests.post("{}{}".format(self.__url, endpoint), + data=json.dumps(data), + headers=_headers, verify=False) + if req.status_code == 409: + LOG.warning(req.text) + raise exceptions.KeystoneUserConflict + if req.status_code not in (200, 201): + LOG.error(req.text) + raise _exception + data = req.json() + logout(_headers) + return data + + def list_projects(self): + return self.__get(endpoint="/projects/", _exception=exceptions.KeystoneProjectError) + + @filter_input + def create_project(self, tenant_dict): + if "name" not in tenant_dict: + raise exceptions.KeystoneProjectError("Cannot get the project name.") + _project = { + "project": { + "description": tenant_dict['description'] if 'description' in tenant_dict else "", + "domain_id": tenant_dict['domain'] if 'domain' in tenant_dict else "default", + "enabled": True, + "is_domain": False, + "name": tenant_dict['name'] + } + } + return self.__post(endpoint="/projects/", + data=_project, + _exception=exceptions.KeystoneProjectError) + + @filter_input + def get_user_by_name(self, username, domain_id="default"): + return self.__get(endpoint="/users?name={}&domain_id={}".format(username, domain_id), + _exception=exceptions.KeystoneUserError) + + @filter_input + def create_user(self, subject_dict): + _user = { + "user": { + "enabled": True, + "name": subject_dict['name'] if 'name' in subject_dict else uuid4().hex, + } + } + if 'project' in subject_dict: + _user['user']['default_project_id'] = subject_dict['project'] + if 'domain' in subject_dict: + _user['user']['domain_id'] = subject_dict['domain'] + if 'password' in subject_dict: + _user['user']['password'] = subject_dict['password'] + try: + return self.__post(endpoint="/users/", + data=_user, + _exception=exceptions.KeystoneUserError) + except exceptions.KeystoneUserConflict: + return True + diff --git a/python_moondb/python_moondb/api/managers.py b/python_moondb/python_moondb/api/managers.py new file mode 100644 index 00000000..602e0f11 --- /dev/null +++ b/python_moondb/python_moondb/api/managers.py @@ -0,0 +1,15 @@ +# 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'. + +from oslo_log import log as logging +LOG = logging.getLogger("moon.db.api.managers") + + +class Managers(object): + """Object that links managers together""" + ModelManager = None + KeystoneManager = None + PDPManager = None + PolicyManager = None diff --git a/python_moondb/python_moondb/api/model.py b/python_moondb/python_moondb/api/model.py new file mode 100644 index 00000000..fbfbb680 --- /dev/null +++ b/python_moondb/python_moondb/api/model.py @@ -0,0 +1,132 @@ +# 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'. + +from uuid import uuid4 +from oslo_log import log as logging +from python_moonutilities import exceptions +from python_moonutilities.security_functions import filter_input, enforce +from python_moondb.api.managers import Managers + + +LOG = logging.getLogger("moon.db.api.model") + + +class ModelManager(Managers): + + def __init__(self, connector=None): + self.driver = connector.driver + Managers.ModelManager = self + + @enforce(("read", "write"), "models") + def update_model(self, user_id, model_id, value): + if model_id not in self.driver.get_models(model_id=model_id): + raise exceptions.ModelUnknown + return self.driver.update_model(model_id=model_id, value=value) + + @enforce(("read", "write"), "models") + def delete_model(self, user_id, model_id): + if model_id not in self.driver.get_models(model_id=model_id): + raise exceptions.ModelUnknown + # TODO (asteroide): check that no policy is connected to this model + return self.driver.delete_model(model_id=model_id) + + @enforce(("read", "write"), "models") + def add_model(self, user_id, model_id=None, value=None): + if model_id in self.driver.get_models(model_id=model_id): + raise exceptions.ModelExisting + if not model_id: + model_id = uuid4().hex + return self.driver.add_model(model_id=model_id, value=value) + + @enforce("read", "models") + def get_models(self, user_id, model_id=None): + return self.driver.get_models(model_id=model_id) + + @enforce(("read", "write"), "meta_rules") + def set_meta_rule(self, user_id, meta_rule_id, value): + if meta_rule_id not in self.driver.get_meta_rules(meta_rule_id=meta_rule_id): + raise exceptions.MetaRuleUnknown + return self.driver.set_meta_rule(meta_rule_id=meta_rule_id, value=value) + + @enforce("read", "meta_rules") + def get_meta_rules(self, user_id, meta_rule_id=None): + return self.driver.get_meta_rules(meta_rule_id=meta_rule_id) + + @enforce(("read", "write"), "meta_rules") + def add_meta_rule(self, user_id, meta_rule_id=None, value=None): + if meta_rule_id in self.driver.get_meta_rules(meta_rule_id=meta_rule_id): + raise exceptions.MetaRuleExisting + if not meta_rule_id: + meta_rule_id = uuid4().hex + LOG.info("add_meta_rule {}".format(value)) + return self.driver.set_meta_rule(meta_rule_id=meta_rule_id, value=value) + + @enforce(("read", "write"), "meta_rules") + def delete_meta_rule(self, user_id, meta_rule_id=None): + if meta_rule_id not in self.driver.get_meta_rules(meta_rule_id=meta_rule_id): + raise exceptions.MetaRuleUnknown + # TODO (asteroide): check and/or delete data and assignments and rules linked to that meta_rule + return self.driver.delete_meta_rule(meta_rule_id=meta_rule_id) + + @enforce("read", "meta_data") + def get_subject_categories(self, user_id, category_id=None): + return self.driver.get_subject_categories(category_id=category_id) + + @enforce(("read", "write"), "meta_data") + def add_subject_category(self, user_id, category_id=None, value=None): + if category_id in self.driver.get_subject_categories(category_id=category_id): + raise exceptions.SubjectCategoryExisting + # if not category_id: + # category_id = uuid4().hex + return self.driver.add_subject_category(name=value["name"], description=value["description"], uuid=category_id) + + @enforce(("read", "write"), "meta_data") + def delete_subject_category(self, user_id, category_id): + # TODO (asteroide): delete all data linked to that category + # TODO (asteroide): delete all meta_rules linked to that category + if category_id not in self.driver.get_subject_categories(category_id=category_id): + raise exceptions.SubjectCategoryUnknown + return self.driver.delete_subject_category(category_id=category_id) + + @enforce("read", "meta_data") + def get_object_categories(self, user_id, category_id=None): + return self.driver.get_object_categories(category_id) + + @enforce(("read", "write"), "meta_data") + def add_object_category(self, user_id, category_id=None, value=None): + if category_id in self.driver.get_object_categories(category_id=category_id): + raise exceptions.ObjectCategoryExisting + # if not category_id: + # category_id = uuid4().hex + return self.driver.add_object_category(name=value["name"], description=value["description"], uuid=category_id) + + @enforce(("read", "write"), "meta_data") + def delete_object_category(self, user_id, category_id): + # TODO (asteroide): delete all data linked to that category + # TODO (asteroide): delete all meta_rules linked to that category + if category_id not in self.driver.get_object_categories(category_id=category_id): + raise exceptions.ObjectCategoryUnknown + return self.driver.delete_object_category(category_id=category_id) + + @enforce("read", "meta_data") + def get_action_categories(self, user_id, category_id=None): + return self.driver.get_action_categories(category_id=category_id) + + @enforce(("read", "write"), "meta_data") + def add_action_category(self, user_id, category_id=None, value=None): + if category_id in self.driver.get_action_categories(category_id=category_id): + raise exceptions.ActionCategoryExisting + # if not category_id: + # category_id = uuid4().hex + return self.driver.add_action_category(name=value["name"], description=value["description"], uuid=category_id) + + @enforce(("read", "write"), "meta_data") + def delete_action_category(self, user_id, category_id): + # TODO (asteroide): delete all data linked to that category + # TODO (asteroide): delete all meta_rules linked to that category + if category_id not in self.driver.get_action_categories(category_id=category_id): + raise exceptions.ActionCategoryExisting + return self.driver.delete_action_category(category_id=category_id) + diff --git a/python_moondb/python_moondb/api/pdp.py b/python_moondb/python_moondb/api/pdp.py new file mode 100644 index 00000000..5fb7aa78 --- /dev/null +++ b/python_moondb/python_moondb/api/pdp.py @@ -0,0 +1,38 @@ +# 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'. + +from uuid import uuid4 +from oslo_log import log as logging +from python_moonutilities.security_functions import filter_input, enforce +from python_moondb.api.managers import Managers + + +LOG = logging.getLogger("moon.db.api.pdp") + + +class PDPManager(Managers): + + def __init__(self, connector=None): + self.driver = connector.driver + Managers.PDPManager = self + + @enforce(("read", "write"), "pdp") + def update_pdp(self, user_id, pdp_id, value): + return self.driver.update_pdp(pdp_id=pdp_id, value=value) + + @enforce(("read", "write"), "pdp") + def delete_pdp(self, user_id, pdp_id): + return self.driver.delete_pdp(pdp_id=pdp_id) + + @enforce(("read", "write"), "pdp") + def add_pdp(self, user_id, pdp_id=None, value=None): + if not pdp_id: + pdp_id = uuid4().hex + return self.driver.add_pdp(pdp_id=pdp_id, value=value) + + @enforce("read", "pdp") + def get_pdp(self, user_id, pdp_id=None): + return self.driver.get_pdp(pdp_id=pdp_id) + diff --git a/python_moondb/python_moondb/api/policy.py b/python_moondb/python_moondb/api/policy.py new file mode 100644 index 00000000..81689826 --- /dev/null +++ b/python_moondb/python_moondb/api/policy.py @@ -0,0 +1,248 @@ +# 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'. + +from uuid import uuid4 +import logging +from python_moonutilities.security_functions import enforce +from python_moondb.api.managers import Managers + +LOG = logging.getLogger("moon.db.api.policy") + + +class PolicyManager(Managers): + + def __init__(self, connector=None): + self.driver = connector.driver + Managers.PolicyManager = self + + def get_policy_from_meta_rules(self, user_id, meta_rule_id): + policies = self.PolicyManager.get_policies("admin") + models = self.ModelManager.get_models("admin") + for pdp_key, pdp_value in self.PDPManager.get_pdp(user_id).items(): + for policy_id in pdp_value["security_pipeline"]: + model_id = policies[policy_id]["model_id"] + if meta_rule_id in models[model_id]["meta_rules"]: + return policy_id + + @enforce(("read", "write"), "policies") + def update_policy(self, user_id, policy_id, value): + return self.driver.update_policy(policy_id=policy_id, value=value) + + @enforce(("read", "write"), "policies") + def delete_policy(self, user_id, policy_id): + # TODO (asteroide): unmap PDP linked to that policy + return self.driver.delete_policy(policy_id=policy_id) + + @enforce(("read", "write"), "policies") + def add_policy(self, user_id, policy_id=None, value=None): + if not policy_id: + policy_id = uuid4().hex + return self.driver.add_policy(policy_id=policy_id, value=value) + + @enforce("read", "policies") + def get_policies(self, user_id, policy_id=None): + return self.driver.get_policies(policy_id=policy_id) + + @enforce("read", "perimeter") + def get_subjects(self, user_id, policy_id, perimeter_id=None): + return self.driver.get_subjects(policy_id=policy_id, perimeter_id=perimeter_id) + + @enforce(("read", "write"), "perimeter") + def add_subject(self, user_id, policy_id, perimeter_id=None, value=None): + k_user = Managers.KeystoneManager.get_user_by_name(value.get('name')) + if not k_user['users']: + k_user = Managers.KeystoneManager.create_user(value) + if not perimeter_id: + try: + LOG.info("k_user={}".format(k_user)) + perimeter_id = k_user['users'][0].get('id', uuid4().hex) + except IndexError: + k_user = Managers.KeystoneManager.get_user_by_name( + value.get('name')) + perimeter_id = uuid4().hex + except KeyError: + k_user = Managers.KeystoneManager.get_user_by_name( + value.get('name')) + perimeter_id = uuid4().hex + value.update(k_user['users'][0]) + return self.driver.set_subject(policy_id=policy_id, perimeter_id=perimeter_id, value=value) + + @enforce(("read", "write"), "perimeter") + def delete_subject(self, user_id, policy_id, perimeter_id): + return self.driver.delete_subject(policy_id=policy_id, perimeter_id=perimeter_id) + + @enforce("read", "perimeter") + def get_objects(self, user_id, policy_id, perimeter_id=None): + return self.driver.get_objects(policy_id=policy_id, perimeter_id=perimeter_id) + + @enforce(("read", "write"), "perimeter") + def add_object(self, user_id, policy_id, perimeter_id=None, value=None): + if not perimeter_id: + perimeter_id = uuid4().hex + return self.driver.set_object(policy_id=policy_id, perimeter_id=perimeter_id, value=value) + + @enforce(("read", "write"), "perimeter") + def delete_object(self, user_id, policy_id, perimeter_id): + return self.driver.delete_object(policy_id=policy_id, perimeter_id=perimeter_id) + + @enforce("read", "perimeter") + def get_actions(self, user_id, policy_id, perimeter_id=None): + return self.driver.get_actions(policy_id=policy_id, perimeter_id=perimeter_id) + + @enforce(("read", "write"), "perimeter") + def add_action(self, user_id, policy_id, perimeter_id=None, value=None): + if not perimeter_id: + perimeter_id = uuid4().hex + return self.driver.set_action(policy_id=policy_id, perimeter_id=perimeter_id, value=value) + + @enforce(("read", "write"), "perimeter") + def delete_action(self, user_id, policy_id, perimeter_id): + return self.driver.delete_action(policy_id=policy_id, perimeter_id=perimeter_id) + + @enforce("read", "data") + def get_subject_data(self, user_id, policy_id, data_id=None, category_id=None): + available_metadata = self.get_available_metadata(user_id, policy_id) + results = [] + if not category_id: + for cat in available_metadata["subject"]: + results.append(self.driver.get_subject_data(policy_id=policy_id, data_id=data_id, + category_id=cat)) + if category_id and category_id in available_metadata["subject"]: + results.append(self.driver.get_subject_data(policy_id=policy_id, data_id=data_id, + category_id=category_id)) + return results + + @enforce(("read", "write"), "data") + def set_subject_data(self, user_id, policy_id, data_id=None, category_id=None, value=None): + if not data_id: + data_id = uuid4().hex + return self.driver.set_subject_data(policy_id=policy_id, data_id=data_id, category_id=category_id, value=value) + + @enforce(("read", "write"), "data") + def delete_subject_data(self, user_id, policy_id, data_id): + # TODO (asteroide): check and/or delete assignments linked to that data + return self.driver.delete_subject_data(policy_id=policy_id, data_id=data_id) + + @enforce("read", "data") + def get_object_data(self, user_id, policy_id, data_id=None, category_id=None): + available_metadata = self.get_available_metadata(user_id, policy_id) + results = [] + if not category_id: + for cat in available_metadata["object"]: + results.append(self.driver.get_object_data(policy_id=policy_id, data_id=data_id, + category_id=cat)) + if category_id and category_id in available_metadata["object"]: + results.append(self.driver.get_object_data(policy_id=policy_id, data_id=data_id, + category_id=category_id)) + return results + + @enforce(("read", "write"), "data") + def add_object_data(self, user_id, policy_id, data_id=None, category_id=None, value=None): + if not data_id: + data_id = uuid4().hex + return self.driver.set_object_data(policy_id=policy_id, data_id=data_id, category_id=category_id, value=value) + + @enforce(("read", "write"), "data") + def delete_object_data(self, user_id, policy_id, data_id): + # TODO (asteroide): check and/or delete assignments linked to that data + return self.driver.delete_object_data(policy_id=policy_id, data_id=data_id) + + @enforce("read", "data") + def get_action_data(self, user_id, policy_id, data_id=None, category_id=None): + available_metadata = self.get_available_metadata(user_id, policy_id) + results = [] + if not category_id: + for cat in available_metadata["action"]: + results.append(self.driver.get_action_data(policy_id=policy_id, data_id=data_id, + category_id=cat)) + if category_id and category_id in available_metadata["action"]: + results.append(self.driver.get_action_data(policy_id=policy_id, data_id=data_id, + category_id=category_id)) + return results + + @enforce(("read", "write"), "data") + def add_action_data(self, user_id, policy_id, data_id=None, category_id=None, value=None): + if not data_id: + data_id = uuid4().hex + return self.driver.set_action_data(policy_id=policy_id, data_id=data_id, category_id=category_id, value=value) + + @enforce(("read", "write"), "data") + def delete_action_data(self, user_id, policy_id, data_id): + # TODO (asteroide): check and/or delete assignments linked to that data + return self.driver.delete_action_data(policy_id=policy_id, data_id=data_id) + + @enforce("read", "assignments") + def get_subject_assignments(self, user_id, policy_id, subject_id=None, category_id=None): + return self.driver.get_subject_assignments(policy_id=policy_id, subject_id=subject_id, category_id=category_id) + + @enforce(("read", "write"), "assignments") + def add_subject_assignment(self, user_id, policy_id, subject_id, category_id, data_id): + return self.driver.add_subject_assignment(policy_id=policy_id, subject_id=subject_id, + category_id=category_id, data_id=data_id) + + @enforce(("read", "write"), "assignments") + def delete_subject_assignment(self, user_id, policy_id, subject_id, category_id, data_id): + return self.driver.delete_subject_assignment(policy_id=policy_id, subject_id=subject_id, + category_id=category_id, data_id=data_id) + + @enforce("read", "assignments") + def get_object_assignments(self, user_id, policy_id, object_id=None, category_id=None): + return self.driver.get_object_assignments(policy_id=policy_id, object_id=object_id, category_id=category_id) + + @enforce(("read", "write"), "assignments") + def add_object_assignment(self, user_id, policy_id, object_id, category_id, data_id): + return self.driver.add_object_assignment(policy_id=policy_id, object_id=object_id, + category_id=category_id, data_id=data_id) + + @enforce(("read", "write"), "assignments") + def delete_object_assignment(self, user_id, policy_id, object_id, category_id, data_id): + return self.driver.delete_object_assignment(policy_id=policy_id, object_id=object_id, + category_id=category_id, data_id=data_id) + + @enforce("read", "assignments") + def get_action_assignments(self, user_id, policy_id, action_id=None, category_id=None): + return self.driver.get_action_assignments(policy_id=policy_id, action_id=action_id, category_id=category_id) + + @enforce(("read", "write"), "assignments") + def add_action_assignment(self, user_id, policy_id, action_id, category_id, data_id): + return self.driver.add_action_assignment(policy_id=policy_id, action_id=action_id, + category_id=category_id, data_id=data_id) + + @enforce(("read", "write"), "assignments") + def delete_action_assignment(self, user_id, policy_id, action_id, category_id, data_id): + return self.driver.delete_action_assignment(policy_id=policy_id, action_id=action_id, + category_id=category_id, data_id=data_id) + + @enforce("read", "rules") + def get_rules(self, user_id, policy_id, meta_rule_id=None, rule_id=None): + return self.driver.get_rules(policy_id=policy_id, meta_rule_id=meta_rule_id, rule_id=rule_id) + + @enforce(("read", "write"), "rules") + def add_rule(self, user_id, policy_id, meta_rule_id, value): + return self.driver.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value) + + @enforce(("read", "write"), "rules") + def delete_rule(self, user_id, policy_id, rule_id): + return self.driver.delete_rule(policy_id=policy_id, rule_id=rule_id) + + @enforce("read", "meta_data") + def get_available_metadata(self, user_id, policy_id): + categories = { + "subject": [], + "object": [], + "action": [] + } + policy = self.driver.get_policies(policy_id=policy_id) + model_id = policy[policy_id]["model_id"] + model = Managers.ModelManager.get_models(user_id=user_id, model_id=model_id) + try: + meta_rule_list = model[model_id]["meta_rules"] + for meta_rule_id in meta_rule_list: + meta_rule = Managers.ModelManager.get_meta_rules(user_id=user_id, meta_rule_id=meta_rule_id) + categories["subject"].extend(meta_rule[meta_rule_id]["subject_categories"]) + categories["object"].extend(meta_rule[meta_rule_id]["object_categories"]) + categories["action"].extend(meta_rule[meta_rule_id]["action_categories"]) + finally: + return categories diff --git a/python_moondb/python_moondb/backends/__init__.py b/python_moondb/python_moondb/backends/__init__.py new file mode 100644 index 00000000..237bdc3e --- /dev/null +++ b/python_moondb/python_moondb/backends/__init__.py @@ -0,0 +1,97 @@ + +""" +intra_extensions = { + intra_extension_id1: { + name: xxx, + model: yyy, + description: zzz}, + intra_extension_id2: {...}, + ... +} + +tenants = { + tenant_id1: { + name: xxx, + description: yyy, + intra_authz_extension_id: zzz, + intra_admin_extension_id: zzz, + }, + tenant_id2: {...}, + ... +} + +--------------- for each intra-extension ----------------- + +subject_categories = { + subject_category_id1: { + name: xxx, + description: yyy}, + subject_category_id2: {...}, + ... +} + +subjects = { + subject_id1: { + name: xxx, + description: yyy, + ...}, + subject_id2: {...}, + ... +} + +subject_scopes = { + subject_category_id1: { + subject_scope_id1: { + name: xxx, + description: aaa}, + subject_scope_id2: { + name: yyy, + description: bbb}, + ...}, + subject_scope_id3: { + ...} + subject_category_id2: {...}, + ... +} + +subject_assignments = { + subject_id1: { + subject_category_id1: [subject_scope_id1, subject_scope_id2, ...], + subject_category_id2: [subject_scope_id3, subject_scope_id4, ...], + ... + }, + subject_id2: { + subject_category_id1: [subject_scope_id1, subject_scope_id2, ...], + subject_category_id2: [subject_scope_id3, subject_scope_id4, ...], + ... + }, + ... +} + +aggregation_algorithm = { + aggregation_algorithm_id: { + name: xxx, + description: yyy + } + } + +sub_meta_rules = { + sub_meta_rule_id_1: { + "name": xxx, + "algorithm": yyy, + "subject_categories": [subject_category_id1, subject_category_id2,...], + "object_categories": [object_category_id1, object_category_id2,...], + "action_categories": [action_category_id1, action_category_id2,...] + sub_meta_rule_id_2: {...}, + ... +} + +rules = { + sub_meta_rule_id1: { + rule_id1: [subject_scope1, subject_scope2, ..., action_scope1, ..., object_scope1, ... ], + rule_id2: [subject_scope3, subject_scope4, ..., action_scope3, ..., object_scope3, ... ], + rule_id3: [thomas, write, admin.subjects] + ...}, + sub_meta_rule_id2: { }, + ...} +""" \ No newline at end of file diff --git a/python_moondb/python_moondb/backends/flat.py b/python_moondb/python_moondb/backends/flat.py new file mode 100644 index 00000000..0fe2f00b --- /dev/null +++ b/python_moondb/python_moondb/backends/flat.py @@ -0,0 +1,89 @@ +# 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 logging +import time +from python_moondb.core import LogDriver + + +class LogConnector(LogDriver): + + AUTHZ_FILE = '/var/log/moon/authz.log' + SYS_FILE = '/var/log/moon/system.log' + TIME_FORMAT = '%Y-%m-%d-%H:%M:%S' + + def __init__(self): + # Fixme (dthom): when logging from an other class, the %appname% in the event + # is always keystone.contrib.moon.backends.flat + super(LogConnector, self).__init__() + + self.SYS_LOG = logging.getLogger(__name__) + if not len(self.SYS_LOG.handlers): + fh = logging.FileHandler(self.SYS_FILE) + fh.setLevel(logging.DEBUG) + formatter = logging.Formatter('%(asctime)s ------ %(message)s', self.TIME_FORMAT) + fh.setFormatter(formatter) + self.SYS_LOG.addHandler(fh) + + self.AUTHZ_LOG = logging.getLogger("authz") + if not len(self.AUTHZ_LOG.handlers): + fh = logging.FileHandler(self.AUTHZ_FILE) + fh.setLevel(logging.WARNING) + formatter = logging.Formatter('%(asctime)s ------ %(message)s', self.TIME_FORMAT) + fh.setFormatter(formatter) + self.AUTHZ_LOG.addHandler(fh) + + def authz(self, message): + self.AUTHZ_LOG.warn(message) + + def debug(self, message): + self.SYS_LOG.debug(message) + + def info(self, message): + self.SYS_LOG.info(message) + + def warning(self, message): + self.SYS_LOG.warning(message) + + def error(self, message): + self.SYS_LOG.error(message) + + def critical(self, message): + self.SYS_LOG.critical(message) + + def get_logs(self, logger="authz", event_number=None, time_from=None, time_to=None, filter_str=None): + if logger == "authz": + _logs = open(self.AUTHZ_FILE).readlines() + else: + _logs = open(self.SYS_FILE).readlines() + if filter_str: + _logs = filter(lambda x: filter_str in x, _logs) + if time_from: + if isinstance(time_from, str): + time_from = time.strptime(time_from.split(" ")[0], self.TIME_FORMAT) + try: + __logs = [] + for log in _logs: + _log = time.strptime(log.split(" ")[0], self.TIME_FORMAT) + if time_from <= _log: + __logs.append(log) + _logs = __logs + except ValueError: + self.error("Time format error") + if time_to: + try: + if isinstance(time_to, str): + time_to = time.strptime(time_to.split(" ")[0], self.TIME_FORMAT) + __logs = [] + for log in _logs: + _log = time.strptime(log.split(" ")[0], self.TIME_FORMAT) + if time_to >= _log: + __logs.append(log) + _logs = __logs + except ValueError: + self.error("Time format error") + if event_number: + _logs = _logs[-event_number:] + return list(_logs) diff --git a/python_moondb/python_moondb/backends/sql.py b/python_moondb/python_moondb/backends/sql.py new file mode 100644 index 00000000..5dba8eb2 --- /dev/null +++ b/python_moondb/python_moondb/backends/sql.py @@ -0,0 +1,1875 @@ +# 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 json +from uuid import uuid4 +import sqlalchemy as sql +import logging +from sqlalchemy.orm import sessionmaker +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import create_engine +from contextlib import contextmanager +from sqlalchemy import types as sql_types +from python_moonutilities import configuration +from python_moonutilities.exceptions import * +from python_moondb.core import PDPDriver, PolicyDriver, ModelDriver + +LOG = logging.getLogger("moon.db.driver.sql") +Base = declarative_base() +DEBUG = True if configuration.get_configuration("logging")['logging']['loggers']['moon']['level'] == "DEBUG" else False + + +class DictBase: + attributes = [] + + @classmethod + def from_dict(cls, d): + new_d = d.copy() + return cls(**new_d) + # new_d = d.copy() + # + # new_d['extra'] = {k: new_d.pop(k) for k in six.iterkeys(d) + # if k not in cls.attributes and k != 'extra'} + # + # return cls(**new_d) + + def to_dict(self): + d = dict() + for attr in self.__class__.attributes: + d[attr] = getattr(self, attr) + return d + + def __getitem__(self, key): + # if "extra" in dir(self) and key in self.extra: + # return self.extra[key] + return getattr(self, key) + + +class JsonBlob(sql_types.TypeDecorator): + + impl = sql.Text + + def process_bind_param(self, value, dialect): + return json.dumps(value) + + def process_result_value(self, value, dialect): + return json.loads(value) + + +class Model(Base, DictBase): + __tablename__ = 'models' + attributes = ['id', 'value'] + id = sql.Column(sql.String(64), primary_key=True) + value = sql.Column(JsonBlob(), nullable=True) + + def to_dict(self): + return { + "name": self.value.get("name"), + "description": self.value.get("description", ""), + "meta_rules": self.value.get("meta_rules", list()), + } + + +class Policy(Base, DictBase): + __tablename__ = 'policies' + attributes = ['id', 'value'] + id = sql.Column(sql.String(64), primary_key=True) + value = sql.Column(JsonBlob(), nullable=True) + + def to_dict(self): + return { + "name": self.value.get("name"), + "description": self.value.get("description", ""), + "model_id": self.value.get("model_id", ""), + "genre": self.value.get("genre", ""), + } + + +class PDP(Base, DictBase): + __tablename__ = 'pdp' + attributes = ['id', 'value'] + id = sql.Column(sql.String(64), primary_key=True) + value = sql.Column(JsonBlob(), nullable=True) + + def to_dict(self): + return { + "name": self.value.get("name"), + "description": self.value.get("description", ""), + "keystone_project_id": self.value.get("keystone_project_id", ""), + "security_pipeline": self.value.get("security_pipeline", []), + } + + +class SubjectCategory(Base, DictBase): + __tablename__ = 'subject_categories' + attributes = ['id', 'name', 'description'] + id = sql.Column(sql.String(64), primary_key=True) + name = sql.Column(sql.String(256), nullable=False) + description = sql.Column(sql.String(256), nullable=True) + + +class ObjectCategory(Base, DictBase): + __tablename__ = 'object_categories' + attributes = ['id', 'name', 'description'] + id = sql.Column(sql.String(64), primary_key=True) + name = sql.Column(sql.String(256), nullable=False) + description = sql.Column(sql.String(256), nullable=True) + + +class ActionCategory(Base, DictBase): + __tablename__ = 'action_categories' + attributes = ['id', 'name', 'description'] + id = sql.Column(sql.String(64), primary_key=True) + name = sql.Column(sql.String(256), nullable=False) + description = sql.Column(sql.String(256), nullable=True) + + +class Subject(Base, DictBase): + __tablename__ = 'subjects' + attributes = ['id', 'value'] + id = sql.Column(sql.String(64), primary_key=True) + value = sql.Column(JsonBlob(), nullable=True) + + def __repr__(self): + return "{}: {}".format(self.id, json.dumps(self.value)) + + def to_return(self): + return { + 'id': self.id, + 'name': self.value.get("name", ""), + 'description': self.value.get("description", ""), + 'email': self.value.get("email", ""), + 'partner_id': self.value.get("partner_id", ""), + 'policy_list': self.value.get("policy_list", []) + } + + def to_dict(self): + return { + 'id': self.id, + 'value': self.value + } + + +class Object(Base, DictBase): + __tablename__ = 'objects' + attributes = ['id', 'value'] + id = sql.Column(sql.String(64), primary_key=True) + value = sql.Column(JsonBlob(), nullable=True) + + def __repr__(self): + return "{}: {}".format(self.id, json.dumps(self.value)) + + def to_dict(self): + return { + 'id': self.id, + 'value': self.value + } + + def to_return(self): + return { + 'id': self.id, + 'name': self.value.get("name", ""), + 'description': self.value.get("description", ""), + 'partner_id': self.value.get("partner_id", ""), + 'policy_list': self.value.get("policy_list", []) + } + + +class Action(Base, DictBase): + __tablename__ = 'actions' + attributes = ['id', 'value'] + id = sql.Column(sql.String(64), primary_key=True) + value = sql.Column(JsonBlob(), nullable=True) + + def __repr__(self): + return "{}: {}".format(self.id, json.dumps(self.value)) + + def to_dict(self): + return { + 'id': self.id, + 'value': self.value + } + + def to_return(self): + return { + 'id': self.id, + 'name': self.value.get("name", ""), + 'description': self.value.get("description", ""), + 'partner_id': self.value.get("partner_id", ""), + 'policy_list': self.value.get("policy_list", []) + } + + +class SubjectData(Base, DictBase): + __tablename__ = 'subject_data' + attributes = ['id', 'value', 'category_id', 'policy_id'] + id = sql.Column(sql.String(64), primary_key=True) + value = sql.Column(JsonBlob(), nullable=True) + category_id = sql.Column(sql.ForeignKey("subject_categories.id"), nullable=False) + policy_id = sql.Column(sql.ForeignKey("policies.id"), nullable=False) + + def to_dict(self): + return { + 'id': self.id, + 'name': self.value.get("name", ""), + 'description': self.value.get("description", ""), + 'category_id': self.category_id, + 'policy_id': self.policy_id + } + + +class ObjectData(Base, DictBase): + __tablename__ = 'object_data' + attributes = ['id', 'value', 'category_id', 'policy_id'] + id = sql.Column(sql.String(64), primary_key=True) + value = sql.Column(JsonBlob(), nullable=True) + category_id = sql.Column(sql.ForeignKey("object_categories.id"), nullable=False) + policy_id = sql.Column(sql.ForeignKey("policies.id"), nullable=False) + + +class ActionData(Base, DictBase): + __tablename__ = 'action_data' + attributes = ['id', 'value', 'category_id', 'policy_id'] + id = sql.Column(sql.String(64), primary_key=True) + value = sql.Column(JsonBlob(), nullable=True) + category_id = sql.Column(sql.ForeignKey("action_categories.id"), nullable=False) + policy_id = sql.Column(sql.ForeignKey("policies.id"), nullable=False) + + +class SubjectAssignment(Base, DictBase): + __tablename__ = 'subject_assignments' + attributes = ['id', 'assignments', 'policy_id', 'subject_id', 'category_id'] + id = sql.Column(sql.String(64), primary_key=True) + assignments = sql.Column(JsonBlob(), nullable=True) + policy_id = sql.Column(sql.ForeignKey("policies.id"), nullable=False) + subject_id = sql.Column(sql.ForeignKey("subjects.id"), nullable=False) + category_id = sql.Column(sql.ForeignKey("subject_categories.id"), nullable=False) + + def to_dict(self): + return { + "id": self.id, + "policy_id": self.policy_id, + "subject_id": self.subject_id, + "category_id": self.category_id, + "assignments": self.assignments, + } + + +class ObjectAssignment(Base, DictBase): + __tablename__ = 'object_assignments' + attributes = ['id', 'assignments', 'policy_id', 'object_id', 'category_id'] + id = sql.Column(sql.String(64), primary_key=True) + assignments = sql.Column(JsonBlob(), nullable=True) + policy_id = sql.Column(sql.ForeignKey("policies.id"), nullable=False) + object_id = sql.Column(sql.ForeignKey("objects.id"), nullable=False) + category_id = sql.Column(sql.ForeignKey("object_categories.id"), nullable=False) + + def to_dict(self): + return { + "id": self.id, + "policy_id": self.policy_id, + "object_id": self.object_id, + "category_id": self.category_id, + "assignments": self.assignments, + } + + +class ActionAssignment(Base, DictBase): + __tablename__ = 'action_assignments' + attributes = ['id', 'assignments', 'policy_id', 'action_id', 'category_id'] + id = sql.Column(sql.String(64), primary_key=True) + assignments = sql.Column(JsonBlob(), nullable=True) + policy_id = sql.Column(sql.ForeignKey("policies.id"), nullable=False) + action_id = sql.Column(sql.ForeignKey("actions.id"), nullable=False) + category_id = sql.Column(sql.ForeignKey("action_categories.id"), nullable=False) + + def to_dict(self): + return { + "id": self.id, + "policy_id": self.policy_id, + "action_id": self.action_id, + "category_id": self.category_id, + "assignments": self.assignments, + } + + +class MetaRule(Base, DictBase): + __tablename__ = 'meta_rules' + attributes = ['id', 'value'] + id = sql.Column(sql.String(64), primary_key=True) + value = sql.Column(JsonBlob(), nullable=True) + + def to_dict(self): + return { + "name": self.value["name"], + "description": self.value.get("description", ""), + "subject_categories": self.value.get("subject_categories", list()), + "object_categories": self.value.get("object_categories", list()), + "action_categories": self.value.get("action_categories", list()), + } + + +class Rule(Base, DictBase): + __tablename__ = 'rules' + attributes = ['id', 'rule', 'policy_id', 'meta_rule_id'] + id = sql.Column(sql.String(64), primary_key=True) + rule = sql.Column(JsonBlob(), nullable=True) + policy_id = sql.Column(sql.ForeignKey("policies.id"), nullable=False) + meta_rule_id = sql.Column(sql.ForeignKey("meta_rules.id"), nullable=False) + + def to_dict(self): + return { + 'id': self.id, + 'rule': self.rule["rule"], + 'instructions': self.rule["instructions"], + 'enabled': self.rule["enabled"], + 'policy_id': self.policy_id, + 'meta_rule_id': self.meta_rule_id + } + + def __repr__(self): + return "{}".format(self.rule) + + +@contextmanager +def session_scope(engine): + """Provide a transactional scope around a series of operations.""" + if type(engine) is str: + echo = DEBUG + engine = create_engine(engine, echo=echo) + session = sessionmaker(bind=engine)() + try: + yield session + session.commit() + except: + session.rollback() + raise + finally: + session.close() + + +class BaseConnector(object): + """Provide a base connector to connect them all""" + engine = "" + + def __init__(self, engine_name): + echo = DEBUG + self.engine = create_engine(engine_name, echo=echo) + + def init_db(self): + Base.metadata.create_all(self.engine) + + def set_engine(self, engine_name): + self.engine = engine_name + + def get_session(self): + return session_scope(self.engine) + + def get_session_for_read(self): + return self.get_session() + + def get_session_for_write(self): + return self.get_session() + + +class PDPConnector(BaseConnector, PDPDriver): + + def update_pdp(self, pdp_id, value): + with self.get_session_for_write() as session: + query = session.query(PDP) + query = query.filter_by(id=pdp_id) + ref = query.first() + if ref: + d = dict(ref.value) + d.update(value) + setattr(ref, "value", d) + return {ref.id: ref.to_dict()} + + def delete_pdp(self, pdp_id): + with self.get_session_for_write() as session: + ref = session.query(PDP).get(pdp_id) + session.delete(ref) + + def add_pdp(self, pdp_id=None, value=None): + with self.get_session_for_write() as session: + new = PDP.from_dict({ + "id": pdp_id if pdp_id else uuid4().hex, + "value": value + }) + session.add(new) + return {new.id: new.to_dict()} + + def get_pdp(self, pdp_id=None): + with self.get_session_for_read() as session: + query = session.query(PDP) + if pdp_id: + query = query.filter_by(id=pdp_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + +class PolicyConnector(BaseConnector, PolicyDriver): + + def update_policy(self, policy_id, value): + with self.get_session_for_write() as session: + query = session.query(Policy) + query = query.filter_by(id=policy_id) + ref = query.first() + if ref: + d = dict(ref.value) + d.update(value) + setattr(ref, "value", d) + return {ref.id: ref.to_dict()} + + def delete_policy(self, policy_id): + with self.get_session_for_write() as session: + ref = session.query(Policy).get(policy_id) + session.delete(ref) + + def add_policy(self, policy_id=None, value=None): + with self.get_session_for_write() as session: + new = Policy.from_dict({ + "id": policy_id if policy_id else uuid4().hex, + "value": value + }) + session.add(new) + return {new.id: new.to_dict()} + + def get_policies(self, policy_id=None): + with self.get_session_for_read() as session: + query = session.query(Policy) + if policy_id: + query = query.filter_by(id=policy_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def get_subjects(self, policy_id, perimeter_id=None): + with self.get_session_for_read() as session: + query = session.query(Subject) + ref_list = copy.deepcopy(query.all()) + if perimeter_id: + for _ref in ref_list: + _ref_value = _ref.to_return() + if perimeter_id == _ref.id: + if policy_id and policy_id in _ref_value["policy_list"]: + return {_ref.id: _ref_value} + else: + return {} + elif policy_id: + results = [] + for _ref in ref_list: + _ref_value = _ref.to_return() + if policy_id in _ref_value["policy_list"]: + results.append(_ref) + return {_ref.id: _ref.to_return() for _ref in results} + return {_ref.id: _ref.to_return() for _ref in ref_list} + + def set_subject(self, policy_id, perimeter_id=None, value=None): + _subject = None + with self.get_session_for_write() as session: + if perimeter_id: + query = session.query(Subject) + query = query.filter_by(id=perimeter_id) + _subject = query.first() + if not _subject: + if "policy_list" not in value or type(value["policy_list"]) is not list: + value["policy_list"] = [] + if policy_id and policy_id not in value["policy_list"]: + value["policy_list"] = [policy_id, ] + new = Subject.from_dict({ + "id": perimeter_id if perimeter_id else uuid4().hex, + "value": value + }) + session.add(new) + return {new.id: new.to_return()} + else: + _value = copy.deepcopy(_subject.to_dict()) + if "policy_list" not in _value["value"] or type(_value["value"]["policy_list"]) is not list: + _value["value"]["policy_list"] = [] + if policy_id and policy_id not in _value["value"]["policy_list"]: + _value["value"]["policy_list"].append(policy_id) + new_subject = Subject.from_dict(_value) + # setattr(_subject, "value", _value["value"]) + setattr(_subject, "value", getattr(new_subject, "value")) + return {_subject.id: _subject.to_return()} + + def delete_subject(self, policy_id, perimeter_id): + with self.get_session_for_write() as session: + query = session.query(Subject) + query = query.filter_by(id=perimeter_id) + _subject = query.first() + if not _subject: + raise SubjectUnknown + old_subject = copy.deepcopy(_subject.to_dict()) + # value = _subject.to_dict() + try: + old_subject["value"]["policy_list"].remove(policy_id) + new_user = Subject.from_dict(old_subject) + setattr(_subject, "value", getattr(new_user, "value")) + except ValueError: + if not _subject.value["policy_list"]: + session.delete(_subject) + + def get_objects(self, policy_id, perimeter_id=None): + with self.get_session_for_read() as session: + query = session.query(Object) + ref_list = copy.deepcopy(query.all()) + if perimeter_id: + for _ref in ref_list: + _ref_value = _ref.to_return() + if perimeter_id == _ref.id: + if policy_id and policy_id in _ref_value["policy_list"]: + return {_ref.id: _ref_value} + else: + return {} + elif policy_id: + results = [] + for _ref in ref_list: + _ref_value = _ref.to_return() + if policy_id in _ref_value["policy_list"]: + results.append(_ref) + return {_ref.id: _ref.to_return() for _ref in results} + return {_ref.id: _ref.to_return() for _ref in ref_list} + + def set_object(self, policy_id, perimeter_id=None, value=None): + _object = None + with self.get_session_for_write() as session: + if perimeter_id: + query = session.query(Object) + query = query.filter_by(id=perimeter_id) + _object = query.first() + if not _object: + if "policy_list" not in value or type(value["policy_list"]) is not list: + value["policy_list"] = [] + if policy_id and policy_id not in value["policy_list"]: + value["policy_list"] = [policy_id, ] + new = Object.from_dict({ + "id": perimeter_id if perimeter_id else uuid4().hex, + "value": value + }) + session.add(new) + return {new.id: new.to_return()} + else: + _value = copy.deepcopy(_object.to_dict()) + if "policy_list" not in _value["value"] or type(_value["value"]["policy_list"]) is not list: + _value["value"]["policy_list"] = [] + if policy_id and policy_id not in _value["value"]["policy_list"]: + _value["value"]["policy_list"].append(policy_id) + new_object = Object.from_dict(_value) + # setattr(_object, "value", _value["value"]) + setattr(_object, "value", getattr(new_object, "value")) + return {_object.id: _object.to_return()} + + def delete_object(self, policy_id, perimeter_id): + with self.get_session_for_write() as session: + query = session.query(Object) + query = query.filter_by(id=perimeter_id) + _object = query.first() + if not _object: + raise ObjectUnknown + old_object = copy.deepcopy(_object.to_dict()) + # value = _object.to_dict() + try: + old_object["value"]["policy_list"].remove(policy_id) + new_user = Object.from_dict(old_object) + setattr(_object, "value", getattr(new_user, "value")) + except ValueError: + if not _object.value["policy_list"]: + session.delete(_object) + + def get_actions(self, policy_id, perimeter_id=None): + with self.get_session_for_read() as session: + query = session.query(Action) + ref_list = copy.deepcopy(query.all()) + if perimeter_id: + for _ref in ref_list: + _ref_value = _ref.to_return() + if perimeter_id == _ref.id: + if policy_id and policy_id in _ref_value["policy_list"]: + return {_ref.id: _ref_value} + else: + return {} + elif policy_id: + results = [] + for _ref in ref_list: + _ref_value = _ref.to_return() + if policy_id in _ref_value["policy_list"]: + results.append(_ref) + return {_ref.id: _ref.to_return() for _ref in results} + return {_ref.id: _ref.to_return() for _ref in ref_list} + + def set_action(self, policy_id, perimeter_id=None, value=None): + _action = None + with self.get_session_for_write() as session: + if perimeter_id: + query = session.query(Action) + query = query.filter_by(id=perimeter_id) + _action = query.first() + if not _action: + if "policy_list" not in value or type(value["policy_list"]) is not list: + value["policy_list"] = [] + if policy_id and policy_id not in value["policy_list"]: + value["policy_list"] = [policy_id, ] + new = Action.from_dict({ + "id": perimeter_id if perimeter_id else uuid4().hex, + "value": value + }) + session.add(new) + return {new.id: new.to_return()} + else: + _value = copy.deepcopy(_action.to_dict()) + if "policy_list" not in _value["value"] or type(_value["value"]["policy_list"]) is not list: + _value["value"]["policy_list"] = [] + if policy_id and policy_id not in _value["value"]["policy_list"]: + _value["value"]["policy_list"].append(policy_id) + new_action = Action.from_dict(_value) + # setattr(_action, "value", _value["value"]) + setattr(_action, "value", getattr(new_action, "value")) + return {_action.id: _action.to_return()} + + def delete_action(self, policy_id, perimeter_id): + with self.get_session_for_write() as session: + query = session.query(Action) + query = query.filter_by(id=perimeter_id) + _action = query.first() + if not _action: + raise ActionUnknown + old_action = copy.deepcopy(_action.to_dict()) + # value = _action.to_dict() + try: + old_action["value"]["policy_list"].remove(policy_id) + new_user = Action.from_dict(old_action) + setattr(_action, "value", getattr(new_user, "value")) + except ValueError: + if not _action.value["policy_list"]: + session.delete(_action) + + def get_subject_data(self, policy_id, data_id=None, category_id=None): + LOG.info("driver {} {} {}".format(policy_id, data_id, category_id)) + with self.get_session_for_read() as session: + query = session.query(SubjectData) + if data_id: + query = query.filter_by(policy_id=policy_id, id=data_id, category_id=category_id) + else: + query = query.filter_by(policy_id=policy_id, category_id=category_id) + ref_list = query.all() + LOG.info("ref_list={}".format(ref_list)) + return { + "policy_id": policy_id, + "category_id": category_id, + "data": {_ref.id: _ref.to_dict() for _ref in ref_list} + } + + def set_subject_data(self, policy_id, data_id=None, category_id=None, value=None): + with self.get_session_for_write() as session: + query = session.query(SubjectData) + query = query.filter_by(policy_id=policy_id, id=data_id, category_id=category_id) + ref = query.first() + if not ref: + new_ref = SubjectData.from_dict( + { + "id": data_id if data_id else uuid4().hex, + 'value': value, + 'category_id': category_id, + 'policy_id': policy_id, + } + ) + session.add(new_ref) + ref = new_ref + else: + for attr in Subject.attributes: + if attr != 'id': + setattr(ref, attr, getattr(ref, attr)) + # session.flush() + return { + "policy_id": policy_id, + "category_id": category_id, + "data": {ref.id: ref.to_dict()} + } + + def delete_subject_data(self, policy_id, data_id): + with self.get_session_for_write() as session: + query = session.query(SubjectData) + query = query.filter_by(policy_id=policy_id, id=data_id) + ref = query.first() + if ref: + session.delete(ref) + + def get_object_data(self, policy_id, data_id=None, category_id=None): + with self.get_session_for_read() as session: + query = session.query(ObjectData) + if data_id: + query = query.filter_by(policy_id=policy_id, id=data_id, category_id=category_id) + else: + query = query.filter_by(policy_id=policy_id, category_id=category_id) + ref_list = query.all() + return { + "policy_id": policy_id, + "category_id": category_id, + "data": {_ref.id: _ref.to_dict() for _ref in ref_list} + } + + def set_object_data(self, policy_id, data_id=None, category_id=None, value=None): + with self.get_session_for_write() as session: + query = session.query(ObjectData) + query = query.filter_by(policy_id=policy_id, id=data_id, category_id=category_id) + ref = query.first() + if not ref: + new_ref = ObjectData.from_dict( + { + "id": data_id if data_id else uuid4().hex, + 'value': value, + 'category_id': category_id, + 'policy_id': policy_id, + } + ) + session.add(new_ref) + ref = new_ref + else: + for attr in Object.attributes: + if attr != 'id': + setattr(ref, attr, getattr(ref, attr)) + # session.flush() + return { + "policy_id": policy_id, + "category_id": category_id, + "data": {ref.id: ref.to_dict()} + } + + def delete_object_data(self, policy_id, data_id): + with self.get_session_for_write() as session: + query = session.query(ObjectData) + query = query.filter_by(policy_id=policy_id, id=data_id) + ref = query.first() + if ref: + session.delete(ref) + + def get_action_data(self, policy_id, data_id=None, category_id=None): + with self.get_session_for_read() as session: + query = session.query(ActionData) + if data_id: + query = query.filter_by(policy_id=policy_id, id=data_id, category_id=category_id) + else: + query = query.filter_by(policy_id=policy_id, category_id=category_id) + ref_list = query.all() + return { + "policy_id": policy_id, + "category_id": category_id, + "data": {_ref.id: _ref.to_dict() for _ref in ref_list} + } + + def set_action_data(self, policy_id, data_id=None, category_id=None, value=None): + with self.get_session_for_write() as session: + query = session.query(ActionData) + query = query.filter_by(policy_id=policy_id, id=data_id, category_id=category_id) + ref = query.first() + if not ref: + new_ref = ActionData.from_dict( + { + "id": data_id if data_id else uuid4().hex, + 'value': value, + 'category_id': category_id, + 'policy_id': policy_id, + } + ) + session.add(new_ref) + ref = new_ref + else: + for attr in Action.attributes: + if attr != 'id': + setattr(ref, attr, getattr(ref, attr)) + # session.flush() + return { + "policy_id": policy_id, + "category_id": category_id, + "data": {ref.id: ref.to_dict()} + } + + def delete_action_data(self, policy_id, data_id): + with self.get_session_for_write() as session: + query = session.query(ActionData) + query = query.filter_by(policy_id=policy_id, id=data_id) + ref = query.first() + if ref: + session.delete(ref) + + def get_subject_assignments(self, policy_id, subject_id=None, category_id=None): + with self.get_session_for_write() as session: + query = session.query(SubjectAssignment) + if subject_id and category_id: + query = query.filter_by(policy_id=policy_id, subject_id=subject_id, category_id=category_id) + elif subject_id: + query = query.filter_by(policy_id=policy_id, subject_id=subject_id) + else: + query = query.filter_by(policy_id=policy_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def add_subject_assignment(self, policy_id, subject_id, category_id, data_id): + with self.get_session_for_write() as session: + query = session.query(SubjectAssignment) + query = query.filter_by(policy_id=policy_id, subject_id=subject_id, category_id=category_id) + ref = query.first() + if ref: + old_ref = copy.deepcopy(ref.to_dict()) + assignments = old_ref["assignments"] + if data_id not in assignments: + assignments.append(data_id) + setattr(ref, "assignments", assignments) + else: + ref = SubjectAssignment.from_dict( + { + "id": uuid4().hex, + "policy_id": policy_id, + "subject_id": subject_id, + "category_id": category_id, + "assignments": [data_id, ], + } + ) + session.add(ref) + return {ref.id: ref.to_dict()} + + def delete_subject_assignment(self, policy_id, subject_id, category_id, data_id): + with self.get_session_for_write() as session: + query = session.query(SubjectAssignment) + query = query.filter_by(policy_id=policy_id, subject_id=subject_id, category_id=category_id) + ref = query.first() + if ref: + old_ref = copy.deepcopy(ref.to_dict()) + assignments = old_ref["assignments"] + # TODO (asteroide): if data_id is None, delete all + if data_id in assignments: + assignments.remove(data_id) + # FIXME (asteroide): the setattr doesn't work here ; the assignments is not updated in the database + setattr(ref, "assignments", assignments) + if not assignments: + session.delete(ref) + + def get_object_assignments(self, policy_id, object_id=None, category_id=None): + with self.get_session_for_write() as session: + query = session.query(ObjectAssignment) + if object_id and category_id: + query = query.filter_by(policy_id=policy_id, object_id=object_id, category_id=category_id) + elif object_id: + query = query.filter_by(policy_id=policy_id, object_id=object_id) + else: + query = query.filter_by(policy_id=policy_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def add_object_assignment(self, policy_id, object_id, category_id, data_id): + with self.get_session_for_write() as session: + query = session.query(ObjectAssignment) + query = query.filter_by(policy_id=policy_id, object_id=object_id, category_id=category_id) + ref = query.first() + if ref: + old_ref = copy.deepcopy(ref.to_dict()) + assignments = old_ref["assignments"] + if data_id not in assignments: + assignments.append(data_id) + setattr(ref, "assignments", assignments) + else: + ref = ObjectAssignment.from_dict( + { + "id": uuid4().hex, + "policy_id": policy_id, + "object_id": object_id, + "category_id": category_id, + "assignments": [data_id, ], + } + ) + session.add(ref) + return {ref.id: ref.to_dict()} + + def delete_object_assignment(self, policy_id, object_id, category_id, data_id): + with self.get_session_for_write() as session: + query = session.query(ObjectAssignment) + query = query.filter_by(policy_id=policy_id, object_id=object_id, category_id=category_id) + ref = query.first() + if ref: + old_ref = copy.deepcopy(ref.to_dict()) + assignments = old_ref["assignments"] + # TODO (asteroide): if data_id is None, delete all + if data_id in assignments: + assignments.remove(data_id) + # FIXME (asteroide): the setattr doesn't work here ; the assignments is not updated in the database + setattr(ref, "assignments", assignments) + if not assignments: + session.delete(ref) + + def get_action_assignments(self, policy_id, action_id=None, category_id=None): + with self.get_session_for_write() as session: + query = session.query(ActionAssignment) + if action_id and category_id: + query = query.filter_by(policy_id=policy_id, action_id=action_id, category_id=category_id) + elif action_id: + query = query.filter_by(policy_id=policy_id, action_id=action_id) + else: + query = query.filter_by(policy_id=policy_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def add_action_assignment(self, policy_id, action_id, category_id, data_id): + with self.get_session_for_write() as session: + query = session.query(ActionAssignment) + query = query.filter_by(policy_id=policy_id, action_id=action_id, category_id=category_id) + ref = query.first() + if ref: + old_ref = copy.deepcopy(ref.to_dict()) + assignments = old_ref["assignments"] + if data_id not in assignments: + assignments.append(data_id) + setattr(ref, "assignments", assignments) + else: + ref = ActionAssignment.from_dict( + { + "id": uuid4().hex, + "policy_id": policy_id, + "action_id": action_id, + "category_id": category_id, + "assignments": [data_id, ], + } + ) + session.add(ref) + return {ref.id: ref.to_dict()} + + def delete_action_assignment(self, policy_id, action_id, category_id, data_id): + with self.get_session_for_write() as session: + query = session.query(ActionAssignment) + query = query.filter_by(policy_id=policy_id, action_id=action_id, category_id=category_id) + ref = query.first() + if ref: + old_ref = copy.deepcopy(ref.to_dict()) + assignments = old_ref["assignments"] + # TODO (asteroide): if data_id is None, delete all + if data_id in assignments: + assignments.remove(data_id) + # FIXME (asteroide): the setattr doesn't work here ; the assignments is not updated in the database + setattr(ref, "assignments", assignments) + if not assignments: + session.delete(ref) + + def get_rules(self, policy_id, rule_id=None, meta_rule_id=None): + with self.get_session_for_read() as session: + query = session.query(Rule) + if rule_id: + query = query.filter_by(policy_id=policy_id, rule_id=rule_id) + ref = query.first() + return {ref.id: ref.to_dict()} + elif meta_rule_id: + query = query.filter_by(policy_id=policy_id, meta_rule_id=meta_rule_id) + ref_list = query.all() + return { + "meta_rule_id": meta_rule_id, + "policy_id": policy_id, + "rules": list(map(lambda x: x.to_dict(), ref_list)) + } + else: + query = query.filter_by(policy_id=policy_id) + ref_list = query.all() + return { + "policy_id": policy_id, + "rules": list(map(lambda x: x.to_dict(), ref_list)) + } + + def add_rule(self, policy_id, meta_rule_id, value): + with self.get_session_for_write() as session: + query = session.query(Rule) + query = query.filter_by(policy_id=policy_id, meta_rule_id=meta_rule_id) + ref_list = query.all() + rules = list(map(lambda x: x.rule, ref_list)) + if not rules or value not in rules: + LOG.info("add_rule IN IF") + ref = Rule.from_dict( + { + "id": uuid4().hex, + "policy_id": policy_id, + "meta_rule_id": meta_rule_id, + "rule": value + } + ) + session.add(ref) + return {ref.id: ref.to_dict()} + return {} + + def delete_rule(self, policy_id, rule_id): + with self.get_session_for_write() as session: + query = session.query(Rule) + query = query.filter_by(policy_id=policy_id, id=rule_id) + ref = query.first() + if ref: + session.delete(ref) + + +class ModelConnector(BaseConnector, ModelDriver): + + def update_model(self, model_id, value): + with self.get_session_for_write() as session: + query = session.query(Model) + if model_id: + query = query.filter_by(id=model_id) + ref = query.first() + if ref: + d = dict(ref.value) + d.update(value) + setattr(ref, "value", d) + return {ref.id: ref.to_dict()} + + def delete_model(self, model_id): + with self.get_session_for_write() as session: + ref = session.query(Model).get(model_id) + session.delete(ref) + + def add_model(self, model_id=None, value=None): + with self.get_session_for_write() as session: + new = Model.from_dict({ + "id": model_id if model_id else uuid4().hex, + "value": value + }) + session.add(new) + return {new.id: new.to_dict()} + + def get_models(self, model_id=None): + with self.get_session_for_read() as session: + query = session.query(Model) + if model_id: + ref_list = query.filter(Model.id == model_id) + else: + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def set_meta_rule(self, meta_rule_id, value): + with self.get_session_for_write() as session: + query = session.query(MetaRule) + query = query.filter_by(id=meta_rule_id) + ref = query.first() + if not ref: + ref = MetaRule.from_dict( + { + "id": meta_rule_id if meta_rule_id else uuid4().hex, + "value": value + } + ) + session.add(ref) + else: + setattr(ref, "value", value) + return {ref.id: ref.to_dict()} + + def get_meta_rules(self, meta_rule_id=None): + with self.get_session_for_read() as session: + query = session.query(MetaRule) + if meta_rule_id: + query = query.filter_by(id=meta_rule_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def delete_meta_rule(self, meta_rule_id=None): + with self.get_session_for_write() as session: + query = session.query(MetaRule) + query = query.filter_by(id=meta_rule_id) + ref = query.first() + if ref: + session.delete(ref) + + def get_subject_categories(self, category_id=None): + with self.get_session_for_read() as session: + query = session.query(SubjectCategory) + if category_id: + query = query.filter_by(id=category_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def add_subject_category(self, name, description, uuid=None): + with self.get_session_for_write() as session: + query = session.query(SubjectCategory) + query = query.filter_by(name=name) + ref = query.first() + if not ref: + ref = SubjectCategory.from_dict( + { + "id": uuid if uuid else uuid4().hex, + "name": name, + "description": description + } + ) + session.add(ref) + return {ref.id: ref.to_dict()} + + def delete_subject_category(self, category_id): + with self.get_session_for_write() as session: + query = session.query(SubjectCategory) + query = query.filter_by(id=category_id) + ref = query.first() + if ref: + session.delete(ref) + + def get_object_categories(self, category_id=None): + with self.get_session_for_read() as session: + query = session.query(ObjectCategory) + if category_id: + query = query.filter_by(id=category_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def add_object_category(self, name, description, uuid=None): + with self.get_session_for_write() as session: + query = session.query(ObjectCategory) + query = query.filter_by(name=name) + ref = query.first() + if not ref: + ref = ObjectCategory.from_dict( + { + "id": uuid if uuid else uuid4().hex, + "name": name, + "description": description + } + ) + session.add(ref) + return {ref.id: ref.to_dict()} + + def delete_object_category(self, category_id): + with self.get_session_for_write() as session: + query = session.query(ObjectCategory) + query = query.filter_by(id=category_id) + ref = query.first() + if ref: + session.delete(ref) + + def get_action_categories(self, category_id=None): + with self.get_session_for_read() as session: + query = session.query(ActionCategory) + if category_id: + query = query.filter_by(id=category_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def add_action_category(self, name, description, uuid=None): + with self.get_session_for_write() as session: + query = session.query(ActionCategory) + query = query.filter_by(name=name) + ref = query.first() + if not ref: + ref = ActionCategory.from_dict( + { + "id": uuid if uuid else uuid4().hex, + "name": name, + "description": description + } + ) + session.add(ref) + return {ref.id: ref.to_dict()} + + def delete_action_category(self, category_id): + with self.get_session_for_write() as session: + query = session.query(ActionCategory) + query = query.filter_by(id=category_id) + ref = query.first() + if ref: + session.delete(ref) + # Getter and Setter for subject_category + + # def get_subject_categories_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(SubjectCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.subject_category for _ref in ref_list} + # + # def set_subject_category_dict(self, intra_extension_id, subject_category_id, subject_category_dict): + # with self.get_session_for_write() as session: + # query = session.query(SubjectCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=subject_category_id) + # ref = query.first() + # new_ref = SubjectCategory.from_dict( + # { + # "id": subject_category_id, + # 'subject_category': subject_category_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in SubjectCategory.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # # session.flush() + # return {subject_category_id: SubjectCategory.to_dict(ref)['subject_category']} + # + # def del_subject_category(self, intra_extension_id, subject_category_id): + # with self.get_session_for_write() as session: + # query = session.query(SubjectCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=subject_category_id) + # ref = query.first() + # self.del_subject_assignment(intra_extension_id, None, None, None) + # session.delete(ref) + # + # # Getter and Setter for object_category + # + # def get_object_categories_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(ObjectCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.object_category for _ref in ref_list} + # + # def set_object_category_dict(self, intra_extension_id, object_category_id, object_category_dict): + # with self.get_session_for_write() as session: + # query = session.query(ObjectCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=object_category_id) + # ref = query.first() + # new_ref = ObjectCategory.from_dict( + # { + # "id": object_category_id, + # 'object_category': object_category_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in ObjectCategory.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {object_category_id: ObjectCategory.to_dict(ref)['object_category']} + # + # def del_object_category(self, intra_extension_id, object_category_id): + # with self.get_session_for_write() as session: + # query = session.query(ObjectCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=object_category_id) + # ref = query.first() + # self.del_object_assignment(intra_extension_id, None, None, None) + # session.delete(ref) + # + # # Getter and Setter for action_category + # + # def get_action_categories_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(ActionCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.action_category for _ref in ref_list} + # + # def set_action_category_dict(self, intra_extension_id, action_category_id, action_category_dict): + # with self.get_session_for_write() as session: + # query = session.query(ActionCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=action_category_id) + # ref = query.first() + # new_ref = ActionCategory.from_dict( + # { + # "id": action_category_id, + # 'action_category': action_category_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in ActionCategory.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {action_category_id: ActionCategory.to_dict(ref)['action_category']} + # + # def del_action_category(self, intra_extension_id, action_category_id): + # with self.get_session_for_write() as session: + # query = session.query(ActionCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=action_category_id) + # ref = query.first() + # self.del_action_assignment(intra_extension_id, None, None, None) + # session.delete(ref) + + # Perimeter + + # def get_subjects_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(Subject) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.subject for _ref in ref_list} + # + # def set_subject_dict(self, intra_extension_id, subject_id, subject_dict): + # with self.get_session_for_write() as session: + # query = session.query(Subject) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=subject_id) + # ref = query.first() + # # if 'id' in subject_dict: + # # subject_dict['id'] = subject_id + # new_ref = Subject.from_dict( + # { + # "id": subject_id, + # 'subject': subject_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Subject.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {subject_id: Subject.to_dict(ref)['subject']} + # + # def del_subject(self, intra_extension_id, subject_id): + # with self.get_session_for_write() as session: + # query = session.query(Subject) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=subject_id) + # ref = query.first() + # session.delete(ref) + # + # def get_objects_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(Object) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.object for _ref in ref_list} + # + # def set_object_dict(self, intra_extension_id, object_id, object_dict): + # with self.get_session_for_write() as session: + # query = session.query(Object) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=object_id) + # ref = query.first() + # new_ref = Object.from_dict( + # { + # "id": object_id, + # 'object': object_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Object.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {object_id: Object.to_dict(ref)['object']} + # + # def del_object(self, intra_extension_id, object_id): + # with self.get_session_for_write() as session: + # query = session.query(Object) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=object_id) + # ref = query.first() + # session.delete(ref) + # + # def get_actions_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(Action) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.action for _ref in ref_list} + # + # def set_action_dict(self, intra_extension_id, action_id, action_dict): + # with self.get_session_for_write() as session: + # query = session.query(Action) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=action_id) + # ref = query.first() + # new_ref = Action.from_dict( + # { + # "id": action_id, + # 'action': action_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Action.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {action_id: Action.to_dict(ref)['action']} + # + # def del_action(self, intra_extension_id, action_id): + # with self.get_session_for_write() as session: + # query = session.query(Action) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=action_id) + # ref = query.first() + # session.delete(ref) + + # Getter and Setter for subject_scope + + # def get_subject_scopes_dict(self, intra_extension_id, subject_category_id): + # with self.get_session_for_read() as session: + # query = session.query(SubjectScope) + # query = query.filter_by(intra_extension_id=intra_extension_id, subject_category_id=subject_category_id) + # ref_list = query.all() + # return {_ref.id: _ref.subject_scope for _ref in ref_list} + # + # def set_subject_scope_dict(self, intra_extension_id, subject_category_id, subject_scope_id, subject_scope_dict): + # with self.get_session_for_write() as session: + # query = session.query(SubjectScope) + # query = query.filter_by(intra_extension_id=intra_extension_id, subject_category_id=subject_category_id, id=subject_scope_id) + # ref = query.first() + # new_ref = SubjectScope.from_dict( + # { + # "id": subject_scope_id, + # 'subject_scope': subject_scope_dict, + # 'intra_extension_id': intra_extension_id, + # 'subject_category_id': subject_category_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Subject.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {subject_scope_id: SubjectScope.to_dict(ref)['subject_scope']} + # + # def del_subject_scope(self, intra_extension_id, subject_category_id, subject_scope_id): + # with self.get_session_for_write() as session: + # query = session.query(SubjectScope) + # if not subject_category_id or not subject_scope_id: + # query = query.filter_by(intra_extension_id=intra_extension_id) + # for ref in query.all(): + # session.delete(ref) + # else: + # query = query.filter_by(intra_extension_id=intra_extension_id, subject_category_id=subject_category_id, id=subject_scope_id) + # ref = query.first() + # session.delete(ref) + # + # # Getter and Setter for object_category_scope + # + # def get_object_scopes_dict(self, intra_extension_id, object_category_id): + # with self.get_session_for_read() as session: + # query = session.query(ObjectScope) + # query = query.filter_by(intra_extension_id=intra_extension_id, object_category_id=object_category_id) + # ref_list = query.all() + # return {_ref.id: _ref.object_scope for _ref in ref_list} + # + # def set_object_scope_dict(self, intra_extension_id, object_category_id, object_scope_id, object_scope_dict): + # with self.get_session_for_write() as session: + # query = session.query(ObjectScope) + # query = query.filter_by(intra_extension_id=intra_extension_id, object_category_id=object_category_id, id=object_scope_id) + # ref = query.first() + # new_ref = ObjectScope.from_dict( + # { + # "id": object_scope_id, + # 'object_scope': object_scope_dict, + # 'intra_extension_id': intra_extension_id, + # 'object_category_id': object_category_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Object.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {object_scope_id: ObjectScope.to_dict(ref)['object_scope']} + # + # def del_object_scope(self, intra_extension_id, object_category_id, object_scope_id): + # with self.get_session_for_write() as session: + # query = session.query(ObjectScope) + # if not object_category_id or not object_scope_id: + # query = query.filter_by(intra_extension_id=intra_extension_id) + # for ref in query.all(): + # session.delete(ref) + # else: + # query = query.filter_by(intra_extension_id=intra_extension_id, object_category_id=object_category_id, id=object_scope_id) + # ref = query.first() + # session.delete(ref) + # + # # Getter and Setter for action_scope + # + # def get_action_scopes_dict(self, intra_extension_id, action_category_id): + # with self.get_session_for_read() as session: + # query = session.query(ActionScope) + # query = query.filter_by(intra_extension_id=intra_extension_id, action_category_id=action_category_id) + # ref_list = query.all() + # return {_ref.id: _ref.action_scope for _ref in ref_list} + # + # def set_action_scope_dict(self, intra_extension_id, action_category_id, action_scope_id, action_scope_dict): + # with self.get_session_for_write() as session: + # query = session.query(ActionScope) + # query = query.filter_by(intra_extension_id=intra_extension_id, action_category_id=action_category_id, id=action_scope_id) + # ref = query.first() + # new_ref = ActionScope.from_dict( + # { + # "id": action_scope_id, + # 'action_scope': action_scope_dict, + # 'intra_extension_id': intra_extension_id, + # 'action_category_id': action_category_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Action.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {action_scope_id: ActionScope.to_dict(ref)['action_scope']} + # + # def del_action_scope(self, intra_extension_id, action_category_id, action_scope_id): + # with self.get_session_for_write() as session: + # query = session.query(ActionScope) + # if not action_category_id or not action_scope_id: + # query = query.filter_by(intra_extension_id=intra_extension_id) + # for ref in query.all(): + # session.delete(ref) + # else: + # query = query.filter_by(intra_extension_id=intra_extension_id, action_category_id=action_category_id, id=action_scope_id) + # ref = query.first() + # session.delete(ref) + # + # # Getter and Setter for subject_category_assignment + # + # def get_subject_assignment_list(self, intra_extension_id, subject_id, subject_category_id): + # with self.get_session_for_read() as session: + # query = session.query(SubjectAssignment) + # if not subject_id or not subject_category_id or not subject_category_id: + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref = query.all() + # return ref + # else: + # query = query.filter_by(intra_extension_id=intra_extension_id, subject_id=subject_id, subject_category_id=subject_category_id) + # ref = query.first() + # if not ref: + # return list() + # LOG.info("get_subject_assignment_list {}".format(ref.subject_assignment)) + # return list(ref.subject_assignment) + # + # def set_subject_assignment_list(self, intra_extension_id, subject_id, subject_category_id, subject_assignment_list=[]): + # with self.get_session_for_write() as session: + # query = session.query(SubjectAssignment) + # query = query.filter_by(intra_extension_id=intra_extension_id, subject_id=subject_id, subject_category_id=subject_category_id) + # ref = query.first() + # new_ref = SubjectAssignment.from_dict( + # { + # "id": uuid4().hex, + # 'subject_assignment': subject_assignment_list, + # 'intra_extension_id': intra_extension_id, + # 'subject_id': subject_id, + # 'subject_category_id': subject_category_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in SubjectAssignment.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return subject_assignment_list + # + # def add_subject_assignment_list(self, intra_extension_id, subject_id, subject_category_id, subject_scope_id): + # new_subject_assignment_list = self.get_subject_assignment_list(intra_extension_id, subject_id, subject_category_id) + # if subject_scope_id not in new_subject_assignment_list: + # new_subject_assignment_list.append(subject_scope_id) + # return self.set_subject_assignment_list(intra_extension_id, subject_id, subject_category_id, new_subject_assignment_list) + # + # def del_subject_assignment(self, intra_extension_id, subject_id, subject_category_id, subject_scope_id): + # if not subject_id or not subject_category_id or not subject_category_id: + # with self.get_session_for_write() as session: + # for ref in self.get_subject_assignment_list(intra_extension_id, None, None): + # session.delete(ref) + # session.flush() + # return + # new_subject_assignment_list = self.get_subject_assignment_list(intra_extension_id, subject_id, subject_category_id) + # new_subject_assignment_list.remove(subject_scope_id) + # return self.set_subject_assignment_list(intra_extension_id, subject_id, subject_category_id, new_subject_assignment_list) + # + # # Getter and Setter for object_category_assignment + # + # def get_object_assignment_list(self, intra_extension_id, object_id, object_category_id): + # with self.get_session_for_read() as session: + # query = session.query(ObjectAssignment) + # if not object_id or not object_category_id or not object_category_id: + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref = query.all() + # return ref + # else: + # query = query.filter_by(intra_extension_id=intra_extension_id, object_id=object_id, object_category_id=object_category_id) + # ref = query.first() + # if not ref: + # return list() + # return list(ref.object_assignment) + # + # def set_object_assignment_list(self, intra_extension_id, object_id, object_category_id, object_assignment_list=[]): + # with self.get_session_for_write() as session: + # query = session.query(ObjectAssignment) + # query = query.filter_by(intra_extension_id=intra_extension_id, object_id=object_id, object_category_id=object_category_id) + # ref = query.first() + # new_ref = ObjectAssignment.from_dict( + # { + # "id": uuid4().hex, + # 'object_assignment': object_assignment_list, + # 'intra_extension_id': intra_extension_id, + # 'object_id': object_id, + # 'object_category_id': object_category_id + # } + # ) + # if not ref: + # session.add(new_ref) + # else: + # for attr in ObjectAssignment.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return self.get_object_assignment_list(intra_extension_id, object_id, object_category_id) + # + # def add_object_assignment_list(self, intra_extension_id, object_id, object_category_id, object_scope_id): + # new_object_assignment_list = self.get_object_assignment_list(intra_extension_id, object_id, object_category_id) + # if object_scope_id not in new_object_assignment_list: + # new_object_assignment_list.append(object_scope_id) + # return self.set_object_assignment_list(intra_extension_id, object_id, object_category_id, new_object_assignment_list) + # + # def del_object_assignment(self, intra_extension_id, object_id, object_category_id, object_scope_id): + # if not object_id or not object_category_id or not object_category_id: + # with self.get_session_for_write() as session: + # for ref in self.get_object_assignment_list(intra_extension_id, None, None): + # session.delete(ref) + # session.flush() + # return + # new_object_assignment_list = self.get_object_assignment_list(intra_extension_id, object_id, object_category_id) + # new_object_assignment_list.remove(object_scope_id) + # return self.set_object_assignment_list(intra_extension_id, object_id, object_category_id, new_object_assignment_list) + # + # # Getter and Setter for action_category_assignment + # + # def get_action_assignment_list(self, intra_extension_id, action_id, action_category_id): + # with self.get_session_for_read() as session: + # query = session.query(ActionAssignment) + # if not action_id or not action_category_id or not action_category_id: + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref = query.all() + # return ref + # else: + # query = query.filter_by(intra_extension_id=intra_extension_id, action_id=action_id, action_category_id=action_category_id) + # ref = query.first() + # if not ref: + # return list() + # return list(ref.action_assignment) + # + # def set_action_assignment_list(self, intra_extension_id, action_id, action_category_id, action_assignment_list=[]): + # with self.get_session_for_write() as session: + # query = session.query(ActionAssignment) + # query = query.filter_by(intra_extension_id=intra_extension_id, action_id=action_id, action_category_id=action_category_id) + # ref = query.first() + # new_ref = ActionAssignment.from_dict( + # { + # "id": uuid4().hex, + # 'action_assignment': action_assignment_list, + # 'intra_extension_id': intra_extension_id, + # 'action_id': action_id, + # 'action_category_id': action_category_id + # } + # ) + # if not ref: + # session.add(new_ref) + # else: + # for attr in ActionAssignment.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return self.get_action_assignment_list(intra_extension_id, action_id, action_category_id) + # + # def add_action_assignment_list(self, intra_extension_id, action_id, action_category_id, action_scope_id): + # new_action_assignment_list = self.get_action_assignment_list(intra_extension_id, action_id, action_category_id) + # if action_scope_id not in new_action_assignment_list: + # new_action_assignment_list.append(action_scope_id) + # return self.set_action_assignment_list(intra_extension_id, action_id, action_category_id, new_action_assignment_list) + # + # def del_action_assignment(self, intra_extension_id, action_id, action_category_id, action_scope_id): + # if not action_id or not action_category_id or not action_category_id: + # with self.get_session_for_write() as session: + # for ref in self.get_action_assignment_list(intra_extension_id, None, None): + # session.delete(ref) + # session.flush() + # return + # new_action_assignment_list = self.get_action_assignment_list(intra_extension_id, action_id, action_category_id) + # new_action_assignment_list.remove(action_scope_id) + # return self.set_action_assignment_list(intra_extension_id, action_id, action_category_id, new_action_assignment_list) + # + # # Getter and Setter for sub_meta_rule + # + # def get_aggregation_algorithm_id(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(IntraExtension) + # query = query.filter_by(id=intra_extension_id) + # ref = query.first() + # try: + # return {"aggregation_algorithm": ref.intra_extension["aggregation_algorithm"]} + # except KeyError: + # return "" + # + # def set_aggregation_algorithm_id(self, intra_extension_id, aggregation_algorithm_id): + # with self.get_session_for_write() as session: + # query = session.query(IntraExtension) + # query = query.filter_by(id=intra_extension_id) + # ref = query.first() + # intra_extension_dict = dict(ref.intra_extension) + # intra_extension_dict["aggregation_algorithm"] = aggregation_algorithm_id + # setattr(ref, "intra_extension", intra_extension_dict) + # # session.flush() + # return {"aggregation_algorithm": ref.intra_extension["aggregation_algorithm"]} + # + # def del_aggregation_algorithm(self, intra_extension_id): + # with self.get_session_for_write() as session: + # query = session.query(IntraExtension) + # query = query.filter_by(id=intra_extension_id) + # ref = query.first() + # intra_extension_dict = dict(ref.intra_extension) + # intra_extension_dict["aggregation_algorithm"] = "" + # setattr(ref, "intra_extension", intra_extension_dict) + # return self.get_aggregation_algorithm_id(intra_extension_id) + # + # # Getter and Setter for sub_meta_rule + # + # def get_sub_meta_rules_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(SubMetaRule) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.sub_meta_rule for _ref in ref_list} + # + # def set_sub_meta_rule_dict(self, intra_extension_id, sub_meta_rule_id, sub_meta_rule_dict): + # with self.get_session_for_write() as session: + # query = session.query(SubMetaRule) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=sub_meta_rule_id) + # ref = query.first() + # new_ref = SubMetaRule.from_dict( + # { + # "id": sub_meta_rule_id, + # 'sub_meta_rule': sub_meta_rule_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # else: + # _sub_meta_rule_dict = dict(ref.sub_meta_rule) + # _sub_meta_rule_dict.update(sub_meta_rule_dict) + # setattr(new_ref, "sub_meta_rule", _sub_meta_rule_dict) + # for attr in SubMetaRule.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return self.get_sub_meta_rules_dict(intra_extension_id) + # + # def del_sub_meta_rule(self, intra_extension_id, sub_meta_rule_id): + # with self.get_session_for_write() as session: + # query = session.query(SubMetaRule) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=sub_meta_rule_id) + # ref = query.first() + # session.delete(ref) + # + # # Getter and Setter for rules + # + # def get_rules_dict(self, intra_extension_id, sub_meta_rule_id): + # with self.get_session_for_read() as session: + # query = session.query(Rule) + # query = query.filter_by(intra_extension_id=intra_extension_id, sub_meta_rule_id=sub_meta_rule_id) + # ref_list = query.all() + # return {_ref.id: _ref.rule for _ref in ref_list} + # + # def set_rule_dict(self, intra_extension_id, sub_meta_rule_id, rule_id, rule_list): + # with self.get_session_for_write() as session: + # query = session.query(Rule) + # query = query.filter_by(intra_extension_id=intra_extension_id, sub_meta_rule_id=sub_meta_rule_id, id=rule_id) + # ref = query.first() + # new_ref = Rule.from_dict( + # { + # "id": rule_id, + # 'rule': rule_list, + # 'intra_extension_id': intra_extension_id, + # 'sub_meta_rule_id': sub_meta_rule_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Rule.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {rule_id: ref.rule} + # + # def del_rule(self, intra_extension_id, sub_meta_rule_id, rule_id): + # with self.get_session_for_write() as session: + # query = session.query(Rule) + # query = query.filter_by(intra_extension_id=intra_extension_id, sub_meta_rule_id=sub_meta_rule_id, id=rule_id) + # ref = query.first() + # session.delete(ref) + + +class SQLConnector(PDPConnector, PolicyConnector, ModelConnector): + pass + +# class InterExtension(Base): +# __tablename__ = 'inter_extension' +# attributes = [ +# 'id', +# 'requesting_intra_extension_id', +# 'requested_intra_extension_id', +# 'virtual_entity_uuid', +# 'genre', +# 'description', +# ] +# id = sql.Column(sql.String(64), primary_key=True) +# requesting_intra_extension_id = sql.Column(sql.String(64)) +# requested_intra_extension_id = sql.Column(sql.String(64)) +# virtual_entity_uuid = sql.Column(sql.String(64)) +# genre = sql.Column(sql.String(64)) +# description = sql.Column(sql.Text()) +# +# @classmethod +# def from_dict(cls, d): +# """Override parent from_dict() method with a simpler implementation. +# """ +# new_d = d.copy() +# return cls(**new_d) +# +# def to_dict(self): +# """Override parent to_dict() method with a simpler implementation. +# """ +# return dict(six.iteritems(self)) +# +# +# class InterExtensionBaseConnector(InterExtensionDriver): +# +# def get_inter_extensions(self): +# with self.get_session_for_read() as session: +# query = session.query(InterExtension.id) +# interextensions = query.all() +# return [interextension.id for interextension in interextensions] +# +# def create_inter_extensions(self, inter_id, inter_extension): +# with self.get_session_for_read() as session: +# ie_ref = InterExtension.from_dict(inter_extension) +# session.add(ie_ref) +# return InterExtension.to_dict(ie_ref) +# +# def get_inter_extension(self, uuid): +# with self.get_session_for_read() as session: +# query = session.query(InterExtension) +# query = query.filter_by(id=uuid) +# ref = query.first() +# if not ref: +# raise exception.NotFound +# return ref.to_dict() +# +# def delete_inter_extensions(self, inter_extension_id): +# with self.get_session_for_read() as session: +# ref = session.query(InterExtension).get(inter_extension_id) +# session.delete(ref) diff --git a/python_moondb/python_moondb/core.py b/python_moondb/python_moondb/core.py new file mode 100644 index 00000000..49e9f711 --- /dev/null +++ b/python_moondb/python_moondb/core.py @@ -0,0 +1,297 @@ +# 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'. + +from oslo_log import log as logging +from oslo_config import cfg +from stevedore.driver import DriverManager +from python_moonutilities import configuration +from python_moondb.api import model, policy, pdp, keystone + +CONF = cfg.CONF +LOG = logging.getLogger("moon.db") + + +class Driver(DriverManager): + + def __init__(self, driver_name, engine_name): + LOG.info("initialization of Driver {}".format(driver_name)) + super(Driver, self).__init__( + namespace='moon_db.driver', + name=driver_name, + invoke_on_load=True, + invoke_args=(engine_name, ), + ) + + +class ModelDriver(Driver): + + def __init__(self, driver_name, engine_name): + super(ModelDriver, self).__init__(driver_name, engine_name) + + def update_model(self, model_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_model(self, model_id): + raise NotImplementedError() # pragma: no cover + + def add_model(self, model_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def get_models(self, model_id=None): + raise NotImplementedError() # pragma: no cover + + def set_meta_rule(self, meta_rule_id, value): + raise NotImplementedError() # pragma: no cover + + def get_meta_rules(self, meta_rule_id=None): + raise NotImplementedError() # pragma: no cover + + def delete_meta_rule(self, meta_rule_id=None): + raise NotImplementedError() # pragma: no cover + + def get_subject_categories(self, category_id=None): + raise NotImplementedError() # pragma: no cover + + def add_subject_category(self, name, description): + raise NotImplementedError() # pragma: no cover + + def delete_subject_category(self, category_id): + raise NotImplementedError() # pragma: no cover + + def get_object_categories(self, category_id): + raise NotImplementedError() # pragma: no cover + + def add_object_category(self, category_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_object_category(self, category_id): + raise NotImplementedError() # pragma: no cover + + def get_action_categories(self, category_id): + raise NotImplementedError() # pragma: no cover + + def add_action_category(self, category_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_action_category(self, category_id): + raise NotImplementedError() # pragma: no cover + + +class PolicyDriver(Driver): + + def __init__(self, driver_name, engine_name): + super(PolicyDriver, self).__init__(driver_name, engine_name) + + def update_policy(self, policy_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_policy(self, policy_id): + raise NotImplementedError() # pragma: no cover + + def add_policy(self, policy_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def get_policies(self, policy_id=None): + raise NotImplementedError() # pragma: no cover + + def get_subjects(self, policy_id, perimeter_id=None): + raise NotImplementedError() # pragma: no cover + + def set_subject(self, policy_id, perimeter_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def delete_subject(self, policy_id, perimeter_id): + raise NotImplementedError() # pragma: no cover + + def get_objects(self, policy_id, perimeter_id=None): + raise NotImplementedError() # pragma: no cover + + def set_object(self, policy_id, perimeter_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def delete_object(self, policy_id, perimeter_id): + raise NotImplementedError() # pragma: no cover + + def get_actions(self, policy_id, perimeter_id=None): + raise NotImplementedError() # pragma: no cover + + def set_action(self, policy_id, perimeter_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def delete_action(self, policy_id, perimeter_id): + raise NotImplementedError() # pragma: no cover + + def get_subject_data(self, policy_id, data_id=None, category_id=None): + raise NotImplementedError() # pragma: no cover + + def set_subject_data(self, policy_id, data_id=None, category_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def delete_subject_data(self, policy_id, data_id): + raise NotImplementedError() # pragma: no cover + + def get_object_data(self, policy_id, data_id=None, category_id=None): + raise NotImplementedError() # pragma: no cover + + def set_object_data(self, policy_id, data_id=None, category_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def delete_object_data(self, policy_id, data_id): + raise NotImplementedError() # pragma: no cover + + def get_action_data(self, policy_id, data_id=None, category_id=None): + raise NotImplementedError() # pragma: no cover + + def set_action_data(self, policy_id, data_id=None, category_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def delete_action_data(self, policy_id, data_id): + raise NotImplementedError() # pragma: no cover + + def get_subject_assignments(self, policy_id, subject_id=None, category_id=None): + raise NotImplementedError() # pragma: no cover + + def add_subject_assignment(self, policy_id, subject_id, category_id, data_id): + raise NotImplementedError() # pragma: no cover + + def delete_subject_assignment(self, policy_id, subject_id, category_id, data_id): + raise NotImplementedError() # pragma: no cover + + def get_object_assignments(self, policy_id, assignment_id=None): + raise NotImplementedError() # pragma: no cover + + def add_object_assignment(self, policy_id, subject_id, category_id, data_id): + raise NotImplementedError() # pragma: no cover + + def delete_object_assignment(self, policy_id, object_id, category_id, data_id): + raise NotImplementedError() # pragma: no cover + + def get_action_assignments(self, policy_id, assignment_id=None): + raise NotImplementedError() # pragma: no cover + + def add_action_assignment(self, policy_id, action_id, category_id, data_id): + raise NotImplementedError() # pragma: no cover + + def delete_action_assignment(self, policy_id, action_id, category_id, data_id): + raise NotImplementedError() # pragma: no cover + + def get_rules(self, policy_id, rule_id=None, meta_rule_id=None): + raise NotImplementedError() # pragma: no cover + + def add_rule(self, policy_id, meta_rule_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_rule(self, policy_id, rule_id): + raise NotImplementedError() # pragma: no cover + + +class PDPDriver(Driver): + + def __init__(self, driver_name, engine_name): + super(PDPDriver, self).__init__(driver_name, engine_name) + + def update_pdp(self, pdp_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_pdp(self, pdp_id): + raise NotImplementedError() # pragma: no cover + + def add_pdp(self, pdp_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def get_pdp(self, pdp_id=None): + raise NotImplementedError() # pragma: no cover + + +class KeystoneDriver(Driver): + + def __init__(self, driver_name, engine_name): + super(KeystoneDriver, self).__init__(driver_name, engine_name) + + +conf = configuration.get_configuration("database")['database'] +KeystoneManager = keystone.KeystoneManager( + KeystoneDriver(conf['driver'], conf['url']) +) + +ModelManager = model.ModelManager( + ModelDriver(conf['driver'], conf['url']) +) + +PolicyManager = policy.PolicyManager( + PolicyDriver(conf['driver'], conf['url']) +) + +PDPManager = pdp.PDPManager( + PDPDriver(conf['driver'], conf['url']) +) + + +# class LogDriver(object): +# +# def authz(self, message): +# """Log authorization message +# +# :param message: the message to log +# :type message: string +# :return: None +# """ +# raise NotImplementedError() # pragma: no cover +# +# def debug(self, message): +# """Log debug message +# +# :param message: the message to log +# :type message: string +# :return: None +# """ +# raise NotImplementedError() # pragma: no cover +# +# def info(self, message): +# """Log informational message +# +# :param message: the message to log +# :type message: string +# :return: None +# """ +# raise NotImplementedError() # pragma: no cover +# +# def warning(self, message): +# """Log warning message +# +# :param message: the message to log +# :type message: string +# :return: None +# """ +# raise NotImplementedError() # pragma: no cover +# +# def error(self, message): +# """Log error message +# +# :param message: the message to log +# :type message: string +# :return: None +# """ +# raise NotImplementedError() # pragma: no cover +# +# def critical(self, message): +# """Log critical message +# +# :param message: the message to log +# :type message: string +# :return: None +# """ +# raise NotImplementedError() # pragma: no cover +# +# def get_logs(self, options): +# """Get logs +# +# :param options: options to filter log events +# :type options: string eg: "event_number=10,from=2014-01-01-10:10:10,to=2014-01-01-12:10:10,filter=expression" +# :return: a list of log events +# +# TIME_FORMAT is '%Y-%m-%d-%H:%M:%S' +# """ +# raise NotImplementedError() # pragma: no cover diff --git a/python_moondb/python_moondb/db_manager.py b/python_moondb/python_moondb/db_manager.py new file mode 100644 index 00000000..c305284d --- /dev/null +++ b/python_moondb/python_moondb/db_manager.py @@ -0,0 +1,82 @@ +# 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 glob +import importlib +import argparse +import logging +from sqlalchemy import create_engine +from python_moonutilities import configuration +from python_moondb.migrate_repo import versions + + +def init_args(): + parser = argparse.ArgumentParser() + parser.add_argument('command', help='command (upgrade or downgrade)', + nargs=1) + parser.add_argument("--verbose", "-v", action='store_true', + help="verbose mode") + parser.add_argument("--debug", "-d", action='store_true', + help="debug mode") + args = parser.parse_args() + + FORMAT = '%(asctime)-15s %(levelname)s %(message)s' + if args.debug: + logging.basicConfig( + format=FORMAT, + level=logging.DEBUG) + elif args.verbose: + logging.basicConfig( + format=FORMAT, + level=logging.INFO) + else: + logging.basicConfig( + format=FORMAT, + level=logging.WARNING) + + requests_log = logging.getLogger("requests.packages.urllib3") + requests_log.setLevel(logging.WARNING) + requests_log.propagate = True + + logger = logging.getLogger("moon.db.manager") + return args, logger + + +def init_engine(): + db_conf = configuration.get_configuration("database")["database"] + return create_engine(db_conf['url']) + + +def main(command, logger, engine): + files = glob.glob(versions.__path__[0] + "/[0-9][0-9][0-9]*.py") + for filename in files: + filename = os.path.basename(filename).replace(".py", "") + o = importlib.import_module( + "moon_db.migrate_repo.versions.{}".format(filename)) + logger.info("Command is {}".format(command)) + if command in ("upgrade", "u", "up"): + logger.info( + "upgrading moon_db.migrate_repo.versions.{}".format(filename)) + o.upgrade(engine) + elif command in ("downgrade", "d", "down"): + logger.info( + "downgrading moon_db.migrate_repo.versions.{}".format( + filename)) + o.downgrade(engine) + else: + logger.critical("Cannot understand the command!") + + +def run(): + args, logger = init_args() + engine = init_engine() + main(args.command[0], logger, engine) + + +if __name__ == "__main__": + run() diff --git a/python_moondb/python_moondb/migrate_repo/__init__.py b/python_moondb/python_moondb/migrate_repo/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/python_moondb/python_moondb/migrate_repo/versions/001_moon.py b/python_moondb/python_moondb/migrate_repo/versions/001_moon.py new file mode 100644 index 00000000..2cc36140 --- /dev/null +++ b/python_moondb/python_moondb/migrate_repo/versions/001_moon.py @@ -0,0 +1,216 @@ +# 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 sqlalchemy as sql + + +def upgrade(migrate_engine): + meta = sql.MetaData() + meta.bind = migrate_engine + + table = sql.Table( + 'pdp', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('value', sql.Text(), nullable=True), + mysql_engine='InnoDB', + mysql_charset='utf8') + table.create(migrate_engine, checkfirst=True) + + table = sql.Table( + 'policies', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('value', sql.Text(), nullable=True), + mysql_engine='InnoDB', + mysql_charset='utf8') + table.create(migrate_engine, checkfirst=True) + + table = sql.Table( + 'models', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('value', sql.Text(), nullable=True), + mysql_engine='InnoDB', + mysql_charset='utf8') + table.create(migrate_engine, checkfirst=True) + + subject_categories_table = sql.Table( + 'subject_categories', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('description', sql.String(256), nullable=True), + mysql_engine='InnoDB', + mysql_charset='utf8') + subject_categories_table.create(migrate_engine, checkfirst=True) + + object_categories_table = sql.Table( + 'object_categories', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('description', sql.String(256), nullable=True), + mysql_engine='InnoDB', + mysql_charset='utf8') + object_categories_table.create(migrate_engine, checkfirst=True) + + action_categories_table = sql.Table( + 'action_categories', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('description', sql.String(256), nullable=True), + mysql_engine='InnoDB', + mysql_charset='utf8') + action_categories_table.create(migrate_engine, checkfirst=True) + + subjects_table = sql.Table( + 'subjects', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('value', sql.Text(), nullable=True), + mysql_engine='InnoDB', + mysql_charset='utf8') + subjects_table.create(migrate_engine, checkfirst=True) + + objects_table = sql.Table( + 'objects', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('value', sql.Text(), nullable=True), + mysql_engine='InnoDB', + mysql_charset='utf8') + objects_table.create(migrate_engine, checkfirst=True) + + actions_table = sql.Table( + 'actions', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('value', sql.Text(), nullable=True), + mysql_engine='InnoDB', + mysql_charset='utf8') + actions_table.create(migrate_engine, checkfirst=True) + + subject_data_table = sql.Table( + 'subject_data', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('value', sql.Text(), nullable=True), + sql.Column('category_id', sql.ForeignKey("subject_categories.id"), nullable=False), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + mysql_engine='InnoDB', + mysql_charset='utf8') + subject_data_table.create(migrate_engine, checkfirst=True) + + object_data_table = sql.Table( + 'object_data', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('value', sql.Text(), nullable=True), + sql.Column('category_id', sql.ForeignKey("object_categories.id"), nullable=False), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + mysql_engine='InnoDB', + mysql_charset='utf8') + object_data_table.create(migrate_engine, checkfirst=True) + + action_data_table = sql.Table( + 'action_data', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('value', sql.Text(), nullable=True), + sql.Column('category_id', sql.ForeignKey("action_categories.id"), nullable=False), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + mysql_engine='InnoDB', + mysql_charset='utf8') + action_data_table.create(migrate_engine, checkfirst=True) + + subject_assignments_table = sql.Table( + 'subject_assignments', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('assignments', sql.Text(), nullable=True), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + sql.Column('subject_id', sql.ForeignKey("subjects.id"), nullable=False), + sql.Column('category_id', sql.ForeignKey("subject_categories.id"), nullable=False), + mysql_engine='InnoDB', + mysql_charset='utf8') + subject_assignments_table.create(migrate_engine, checkfirst=True) + + object_assignments_table = sql.Table( + 'object_assignments', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('assignments', sql.Text(), nullable=True), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + sql.Column('object_id', sql.ForeignKey("objects.id"), nullable=False), + sql.Column('category_id', sql.ForeignKey("object_categories.id"), nullable=False), + mysql_engine='InnoDB', + mysql_charset='utf8') + object_assignments_table.create(migrate_engine, checkfirst=True) + + action_assignments_table = sql.Table( + 'action_assignments', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('assignments', sql.Text(), nullable=True), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + sql.Column('action_id', sql.ForeignKey("actions.id"), nullable=False), + sql.Column('category_id', sql.ForeignKey("action_categories.id"), nullable=False), + mysql_engine='InnoDB', + mysql_charset='utf8') + action_assignments_table.create(migrate_engine, checkfirst=True) + + meta_rules_table = sql.Table( + 'meta_rules', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('value', sql.Text(), nullable=True), + mysql_engine='InnoDB', + mysql_charset='utf8') + meta_rules_table.create(migrate_engine, checkfirst=True) + + rules_table = sql.Table( + 'rules', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('rule', sql.Text(), nullable=True), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + sql.Column('meta_rule_id', sql.ForeignKey("meta_rules.id"), nullable=False), + mysql_engine='InnoDB', + mysql_charset='utf8') + rules_table.create(migrate_engine, checkfirst=True) + + +def downgrade(migrate_engine): + meta = sql.MetaData() + meta.bind = migrate_engine + + for _table in ( + 'rules', + 'meta_rules', + 'action_assignments', + 'object_assignments', + 'subject_assignments', + 'action_data', + 'object_data', + 'subject_data', + 'actions', + 'objects', + 'subjects', + 'action_categories', + 'object_categories', + 'subject_categories', + 'models', + 'policies', + 'pdp' + ): + try: + table = sql.Table(_table, meta, autoload=True) + table.drop(migrate_engine, checkfirst=True) + except Exception as e: + print(e) + + diff --git a/python_moondb/python_moondb/migrate_repo/versions/__init__.py b/python_moondb/python_moondb/migrate_repo/versions/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/python_moondb/requirements.txt b/python_moondb/requirements.txt new file mode 100644 index 00000000..03afc879 --- /dev/null +++ b/python_moondb/requirements.txt @@ -0,0 +1,6 @@ +stevedore +sqlalchemy +pymysql +requests +oslo.log +oslo.config diff --git a/python_moondb/setup.py b/python_moondb/setup.py new file mode 100644 index 00000000..65687c3f --- /dev/null +++ b/python_moondb/setup.py @@ -0,0 +1,55 @@ +# 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'. + +from setuptools import setup, find_packages +import python_moondb + + +with open('requirements.txt') as f: + required = f.read().splitlines() + +setup( + + name='python-moondb', + + version=python_moondb.__version__, + + packages=find_packages(), + + author="Thomas Duval", + + author_email="thomas.duval@orange.com", + + description="This library is a helper to interact with the Moon database.", + + long_description=open('README.md').read(), + + install_requires=required, + + include_package_data=True, + + url='https://git.opnfv.org/cgit/moon/', + + classifiers=[ + "Programming Language :: Python", + "Development Status :: 1 - Planning", + "License :: OSI Approved", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + ], + + entry_points={ + "moon_db.driver": + [ + "sql = python_moondb.backends.sql:SQLConnector", + "flat = python_moondb.backends.flat:LogConnector", + ], + 'console_scripts': [ + 'moon_db_manager = python_moondb.db_manager:run', + ], + } + +) diff --git a/python_moondb/tests/unit_python/conftest.py b/python_moondb/tests/unit_python/conftest.py new file mode 100644 index 00000000..c2e5e579 --- /dev/null +++ b/python_moondb/tests/unit_python/conftest.py @@ -0,0 +1,145 @@ +import base64 +import json +import logging +import os +import pytest +import requests_mock +import mock_components +import mock_keystone + +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" + } +} + + +@pytest.fixture +def db(): + return CONF['database'] + + +@pytest.fixture(autouse=True) +def set_consul_and_db(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) + + from moon_db.db_manager import init_engine, main + engine = init_engine() + main("upgrade", logging.getLogger("db_manager"), engine) + yield m + os.unlink(CONF['database']['url'].replace("sqlite:///", "")) + + diff --git a/python_moondb/tests/unit_python/mock_components.py b/python_moondb/tests/unit_python/mock_components.py new file mode 100644 index 00000000..a0319e1a --- /dev/null +++ b/python_moondb/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/python_moondb/tests/unit_python/mock_keystone.py b/python_moondb/tests/unit_python/mock_keystone.py new file mode 100644 index 00000000..c0b26b88 --- /dev/null +++ b/python_moondb/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/python_moondb/tests/unit_python/requirements.txt b/python_moondb/tests/unit_python/requirements.txt new file mode 100644 index 00000000..5f507ff7 --- /dev/null +++ b/python_moondb/tests/unit_python/requirements.txt @@ -0,0 +1,5 @@ +sqlalchemy +pymysql +pytest +requests_mock +python_moonutilities \ No newline at end of file diff --git a/python_moondb/tests/unit_python/test_policies.py b/python_moondb/tests/unit_python/test_policies.py new file mode 100644 index 00000000..3bd1360e --- /dev/null +++ b/python_moondb/tests/unit_python/test_policies.py @@ -0,0 +1,77 @@ +# 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'. + + +def get_policies(): + from moon_db.core import PolicyManager + return PolicyManager.get_policies("admin") + + +def add_policies(value=None): + from moon_db.core import PolicyManager + if not value: + value = { + "name": "test_policiy", + "model_id": "", + "genre": "authz", + "description": "test", + } + return PolicyManager.add_policy("admin", value=value) + + +def delete_policies(uuid=None, name=None): + from moon_db.core import PolicyManager + if not uuid: + for policy_id, policy_value in get_policies(): + if name == policy_value['name']: + uuid = policy_id + break + PolicyManager.delete_policy("admin", uuid) + + +def test_get_policies(db): + policies = get_policies() + assert isinstance(policies, dict) + assert not policies + + +def test_add_policies(db): + value = { + "name": "test_policy", + "model_id": "", + "genre": "authz", + "description": "test", + } + policies = add_policies(value) + assert isinstance(policies, dict) + assert policies + assert len(policies.keys()) == 1 + policy_id = list(policies.keys())[0] + for key in ("genre", "name", "model_id", "description"): + assert key in policies[policy_id] + assert policies[policy_id][key] == value[key] + + +def test_delete_policies(db): + value = { + "name": "test_policy1", + "model_id": "", + "genre": "authz", + "description": "test", + } + policies = add_policies(value) + policy_id1 = list(policies.keys())[0] + value = { + "name": "test_policy2", + "model_id": "", + "genre": "authz", + "description": "test", + } + policies = add_policies(value) + policy_id2 = list(policies.keys())[0] + assert policy_id1 != policy_id2 + delete_policies(policy_id1) + policies = get_policies() + assert policy_id1 not in policies diff --git a/python_moondb/tests/unit_python/utilities.py b/python_moondb/tests/unit_python/utilities.py new file mode 100644 index 00000000..1d79d890 --- /dev/null +++ b/python_moondb/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') -- cgit 1.2.3-korg