From ce23db0a967dcfe14b71719d6f2a296419a2fa55 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Sat, 17 Oct 2015 16:03:06 -0400 Subject: [PATCH] Retire stackforge/graffiti --- .coveragerc | 7 - .gitignore | 52 - .gitreview | 4 - .mailmap | 3 - .testr.conf | 7 - CONTRIBUTING.rst | 16 - HACKING.rst | 4 - LICENSE | 175 ---- MANIFEST.in | 6 - README.rst | 16 +- babel.cfg | 1 - config.py | 156 --- doc/source/conf.py | 75 -- doc/source/contributing.rst | 1 - doc/source/index.rst | 24 - doc/source/installation.rst | 12 - doc/source/readme.rst | 1 - doc/source/usage.rst | 7 - etc/dictionary/CapabilityType-Samples.json | 196 ---- .../CapabilityType-os-compute-cpu.json | 268 ------ .../CapabilityType-os-compute-guest.json | 861 ----------------- .../CapabilityType-os-compute-host.json | 354 ------- etc/dictionary/CapabilityType-os-glance.json | 45 - etc/dictionary/CapabilityType-trust.json | 43 - ...CapabilityType_ApplicationDevelopment.json | 252 ----- etc/dictionary/Namespaces.json | 42 - etc/graffiti.conf.sample | 11 - etc/temp-token.txt | 1 - graffiti/__init__.py | 0 graffiti/api/__init__.py | 0 graffiti/api/app.py | 57 -- graffiti/api/controllers/__init__.py | 0 graffiti/api/controllers/root.py | 33 - graffiti/api/controllers/v1/__init__.py | 0 .../api/controllers/v1/capability_type.py | 144 --- .../controllers/v1/capability_type_batch.py | 102 -- .../controllers/v1/capability_type_derived.py | 50 - graffiti/api/controllers/v1/namespace.py | 71 -- graffiti/api/controllers/v1/resource.py | 229 ----- graffiti/api/controllers/versions.py | 25 - graffiti/api/hooks.py | 37 - graffiti/api/model/__init__.py | 18 - graffiti/api/model/v1/__init__.py | 0 graffiti/api/model/v1/capability.py | 29 - graffiti/api/model/v1/capability_type.py | 33 - .../model/v1/capability_type_derived_prop.py | 36 - graffiti/api/model/v1/capability_type_key.py | 33 - graffiti/api/model/v1/dao/__init__.py | 0 graffiti/api/model/v1/dao/captype_dao.py | 42 - .../api/model/v1/dao/captype_dao_factory.py | 41 - graffiti/api/model/v1/dao/captype_db_dao.py | 157 --- graffiti/api/model/v1/dao/captype_file_dao.py | 87 -- graffiti/api/model/v1/dao/captype_mem_dao.py | 55 -- graffiti/api/model/v1/dao/ns_dao.py | 39 - graffiti/api/model/v1/dao/ns_dao_factory.py | 57 -- graffiti/api/model/v1/dao/ns_db_dao.py | 57 -- graffiti/api/model/v1/dao/ns_file_dao.py | 86 -- graffiti/api/model/v1/dao/ns_mem_dao.py | 49 - graffiti/api/model/v1/dao/resource_dao.py | 36 - .../api/model/v1/dao/resource_dao_factory.py | 38 - graffiti/api/model/v1/dao/resource_db_dao.py | 40 - .../api/model/v1/dao/resource_file_dao.py | 42 - graffiti/api/model/v1/dao/resource_mem_dao.py | 51 - .../api/model/v1/derived_property_type.py | 37 - graffiti/api/model/v1/derived_type.py | 27 - graffiti/api/model/v1/namespace.py | 29 - graffiti/api/model/v1/property.py | 27 - graffiti/api/model/v1/property_item_type.py | 27 - graffiti/api/model/v1/property_type.py | 50 - graffiti/api/model/v1/provider.py | 26 - graffiti/api/model/v1/requirement.py | 29 - graffiti/api/model/v1/resource.py | 39 - graffiti/api/model/v1/resource_query.py | 26 - graffiti/api/service.py | 31 - graffiti/api/tests/__init__.py | 14 - graffiti/api/tests/base.py | 82 -- graffiti/api/tests/pecan_base.py | 119 --- .../samples/captypes_os-glance-2014-1.json | 555 ----------- .../api/tests/samples/resource_2014-1.json | 47 - graffiti/api/tests/test_controller_v1.py | 94 -- graffiti/api/tests/test_graffiti.py | 68 -- graffiti/common/__init__.py | 0 graffiti/common/db_utils.py | 44 - graffiti/common/driver_factory.py | 149 --- graffiti/common/exception.py | 87 -- graffiti/common/utilities/__init__.py | 0 .../common/utilities/capability_type_tree.py | 133 --- .../utilities/capability_type_tree_node.py | 22 - graffiti/common/utils.py | 202 ---- graffiti/db/__init__.py | 0 graffiti/db/api.py | 263 ------ graffiti/db/migration/README | 80 -- graffiti/db/migration/__init__.py | 0 graffiti/db/migration/alembic.ini | 60 -- .../db/migration/alembic_migrations/README | 1 - .../db/migration/alembic_migrations/env.py | 86 -- .../alembic_migrations/script.py.mako | 22 - .../versions/001_create_dictionary_tables.py | 59 -- graffiti/db/models.py | 86 -- graffiti/drivers/__init__.py | 1 - graffiti/drivers/base.py | 107 --- graffiti/drivers/cinder.py | 33 - graffiti/drivers/glance.py | 32 - graffiti/drivers/local.py | 33 - graffiti/drivers/modules/__init__.py | 0 graffiti/drivers/modules/cinder.py | 262 ----- graffiti/drivers/modules/glance.py | 277 ------ graffiti/drivers/modules/local.py | 102 -- graffiti/drivers/modules/nova.py | 316 ------- graffiti/drivers/nova.py | 32 - graffiti/openstack/__init__.py | 0 graffiti/openstack/common/__init__.py | 2 - graffiti/openstack/common/context.py | 111 --- graffiti/openstack/common/db/__init__.py | 0 graffiti/openstack/common/db/api.py | 162 ---- graffiti/openstack/common/db/exception.py | 56 -- graffiti/openstack/common/db/options.py | 171 ---- .../common/db/sqlalchemy/__init__.py | 0 .../common/db/sqlalchemy/migration.py | 268 ------ .../openstack/common/db/sqlalchemy/models.py | 115 --- .../common/db/sqlalchemy/provision.py | 187 ---- .../openstack/common/db/sqlalchemy/session.py | 892 ------------------ .../openstack/common/db/sqlalchemy/utils.py | 638 ------------- graffiti/openstack/common/excutils.py | 99 -- graffiti/openstack/common/fileutils.py | 135 --- graffiti/openstack/common/gettextutils.py | 474 ---------- graffiti/openstack/common/importutils.py | 73 -- graffiti/openstack/common/jsonutils.py | 174 ---- graffiti/openstack/common/local.py | 45 - graffiti/openstack/common/lockutils.py | 377 -------- graffiti/openstack/common/log.py | 711 -------------- graffiti/openstack/common/processutils.py | 267 ------ graffiti/openstack/common/test.py | 99 -- graffiti/openstack/common/timeutils.py | 210 ----- graffiti/tests/__init__.py | 0 graffiti/tests/base.py | 283 ------ graffiti/tests/db/__init__.py | 0 graffiti/tests/db/test_db_api.py | 140 --- graffiti/tests/drivers/__init__.py | 0 .../tests/drivers/test_db_resource_driver.py | 32 - .../drivers/test_glance_resource_driver.py | 32 - graffiti/tests/tools/mock_glance_image.py | 319 ------- openstack-common.conf | 6 - requirements.txt | 15 - setup.cfg | 53 -- setup.py | 22 - test-requirements.txt | 15 - tox.ini | 31 - 148 files changed, 5 insertions(+), 14439 deletions(-) delete mode 100644 .coveragerc delete mode 100644 .gitignore delete mode 100644 .gitreview delete mode 100644 .mailmap delete mode 100644 .testr.conf delete mode 100644 CONTRIBUTING.rst delete mode 100644 HACKING.rst delete mode 100644 LICENSE delete mode 100644 MANIFEST.in delete mode 100644 babel.cfg delete mode 100644 config.py delete mode 100755 doc/source/conf.py delete mode 100644 doc/source/contributing.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/installation.rst delete mode 100644 doc/source/readme.rst delete mode 100644 doc/source/usage.rst delete mode 100644 etc/dictionary/CapabilityType-Samples.json delete mode 100644 etc/dictionary/CapabilityType-os-compute-cpu.json delete mode 100644 etc/dictionary/CapabilityType-os-compute-guest.json delete mode 100644 etc/dictionary/CapabilityType-os-compute-host.json delete mode 100644 etc/dictionary/CapabilityType-os-glance.json delete mode 100644 etc/dictionary/CapabilityType-trust.json delete mode 100644 etc/dictionary/CapabilityType_ApplicationDevelopment.json delete mode 100644 etc/dictionary/Namespaces.json delete mode 100644 etc/graffiti.conf.sample delete mode 100644 etc/temp-token.txt delete mode 100644 graffiti/__init__.py delete mode 100644 graffiti/api/__init__.py delete mode 100644 graffiti/api/app.py delete mode 100644 graffiti/api/controllers/__init__.py delete mode 100644 graffiti/api/controllers/root.py delete mode 100644 graffiti/api/controllers/v1/__init__.py delete mode 100644 graffiti/api/controllers/v1/capability_type.py delete mode 100644 graffiti/api/controllers/v1/capability_type_batch.py delete mode 100644 graffiti/api/controllers/v1/capability_type_derived.py delete mode 100644 graffiti/api/controllers/v1/namespace.py delete mode 100644 graffiti/api/controllers/v1/resource.py delete mode 100644 graffiti/api/controllers/versions.py delete mode 100644 graffiti/api/hooks.py delete mode 100644 graffiti/api/model/__init__.py delete mode 100644 graffiti/api/model/v1/__init__.py delete mode 100644 graffiti/api/model/v1/capability.py delete mode 100644 graffiti/api/model/v1/capability_type.py delete mode 100644 graffiti/api/model/v1/capability_type_derived_prop.py delete mode 100644 graffiti/api/model/v1/capability_type_key.py delete mode 100644 graffiti/api/model/v1/dao/__init__.py delete mode 100644 graffiti/api/model/v1/dao/captype_dao.py delete mode 100644 graffiti/api/model/v1/dao/captype_dao_factory.py delete mode 100644 graffiti/api/model/v1/dao/captype_db_dao.py delete mode 100644 graffiti/api/model/v1/dao/captype_file_dao.py delete mode 100644 graffiti/api/model/v1/dao/captype_mem_dao.py delete mode 100755 graffiti/api/model/v1/dao/ns_dao.py delete mode 100755 graffiti/api/model/v1/dao/ns_dao_factory.py delete mode 100755 graffiti/api/model/v1/dao/ns_db_dao.py delete mode 100755 graffiti/api/model/v1/dao/ns_file_dao.py delete mode 100755 graffiti/api/model/v1/dao/ns_mem_dao.py delete mode 100644 graffiti/api/model/v1/dao/resource_dao.py delete mode 100644 graffiti/api/model/v1/dao/resource_dao_factory.py delete mode 100644 graffiti/api/model/v1/dao/resource_db_dao.py delete mode 100644 graffiti/api/model/v1/dao/resource_file_dao.py delete mode 100644 graffiti/api/model/v1/dao/resource_mem_dao.py delete mode 100644 graffiti/api/model/v1/derived_property_type.py delete mode 100644 graffiti/api/model/v1/derived_type.py delete mode 100644 graffiti/api/model/v1/namespace.py delete mode 100644 graffiti/api/model/v1/property.py delete mode 100755 graffiti/api/model/v1/property_item_type.py delete mode 100644 graffiti/api/model/v1/property_type.py delete mode 100644 graffiti/api/model/v1/provider.py delete mode 100644 graffiti/api/model/v1/requirement.py delete mode 100644 graffiti/api/model/v1/resource.py delete mode 100644 graffiti/api/model/v1/resource_query.py delete mode 100644 graffiti/api/service.py delete mode 100644 graffiti/api/tests/__init__.py delete mode 100644 graffiti/api/tests/base.py delete mode 100644 graffiti/api/tests/pecan_base.py delete mode 100644 graffiti/api/tests/samples/captypes_os-glance-2014-1.json delete mode 100644 graffiti/api/tests/samples/resource_2014-1.json delete mode 100644 graffiti/api/tests/test_controller_v1.py delete mode 100644 graffiti/api/tests/test_graffiti.py delete mode 100644 graffiti/common/__init__.py delete mode 100644 graffiti/common/db_utils.py delete mode 100644 graffiti/common/driver_factory.py delete mode 100644 graffiti/common/exception.py delete mode 100644 graffiti/common/utilities/__init__.py delete mode 100644 graffiti/common/utilities/capability_type_tree.py delete mode 100644 graffiti/common/utilities/capability_type_tree_node.py delete mode 100644 graffiti/common/utils.py delete mode 100644 graffiti/db/__init__.py delete mode 100644 graffiti/db/api.py delete mode 100644 graffiti/db/migration/README delete mode 100644 graffiti/db/migration/__init__.py delete mode 100644 graffiti/db/migration/alembic.ini delete mode 100644 graffiti/db/migration/alembic_migrations/README delete mode 100644 graffiti/db/migration/alembic_migrations/env.py delete mode 100644 graffiti/db/migration/alembic_migrations/script.py.mako delete mode 100644 graffiti/db/migration/alembic_migrations/versions/001_create_dictionary_tables.py delete mode 100644 graffiti/db/models.py delete mode 100644 graffiti/drivers/__init__.py delete mode 100644 graffiti/drivers/base.py delete mode 100644 graffiti/drivers/cinder.py delete mode 100644 graffiti/drivers/glance.py delete mode 100644 graffiti/drivers/local.py delete mode 100644 graffiti/drivers/modules/__init__.py delete mode 100644 graffiti/drivers/modules/cinder.py delete mode 100644 graffiti/drivers/modules/glance.py delete mode 100644 graffiti/drivers/modules/local.py delete mode 100644 graffiti/drivers/modules/nova.py delete mode 100644 graffiti/drivers/nova.py delete mode 100644 graffiti/openstack/__init__.py delete mode 100644 graffiti/openstack/common/__init__.py delete mode 100644 graffiti/openstack/common/context.py delete mode 100644 graffiti/openstack/common/db/__init__.py delete mode 100644 graffiti/openstack/common/db/api.py delete mode 100644 graffiti/openstack/common/db/exception.py delete mode 100644 graffiti/openstack/common/db/options.py delete mode 100644 graffiti/openstack/common/db/sqlalchemy/__init__.py delete mode 100644 graffiti/openstack/common/db/sqlalchemy/migration.py delete mode 100644 graffiti/openstack/common/db/sqlalchemy/models.py delete mode 100644 graffiti/openstack/common/db/sqlalchemy/provision.py delete mode 100644 graffiti/openstack/common/db/sqlalchemy/session.py delete mode 100644 graffiti/openstack/common/db/sqlalchemy/utils.py delete mode 100644 graffiti/openstack/common/excutils.py delete mode 100644 graffiti/openstack/common/fileutils.py delete mode 100644 graffiti/openstack/common/gettextutils.py delete mode 100644 graffiti/openstack/common/importutils.py delete mode 100644 graffiti/openstack/common/jsonutils.py delete mode 100644 graffiti/openstack/common/local.py delete mode 100644 graffiti/openstack/common/lockutils.py delete mode 100644 graffiti/openstack/common/log.py delete mode 100644 graffiti/openstack/common/processutils.py delete mode 100644 graffiti/openstack/common/test.py delete mode 100644 graffiti/openstack/common/timeutils.py delete mode 100644 graffiti/tests/__init__.py delete mode 100644 graffiti/tests/base.py delete mode 100644 graffiti/tests/db/__init__.py delete mode 100644 graffiti/tests/db/test_db_api.py delete mode 100644 graffiti/tests/drivers/__init__.py delete mode 100644 graffiti/tests/drivers/test_db_resource_driver.py delete mode 100644 graffiti/tests/drivers/test_glance_resource_driver.py delete mode 100644 graffiti/tests/tools/mock_glance_image.py delete mode 100644 openstack-common.conf delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100755 setup.py delete mode 100644 test-requirements.txt delete mode 100644 tox.ini diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index d5c7ff0..0000000 --- a/.coveragerc +++ /dev/null @@ -1,7 +0,0 @@ -[run] -branch = True -source = graffiti -omit = graffiti/tests/*,graffiti/openstack/* - -[report] -ignore-errors = True \ No newline at end of file diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ff9d662..0000000 --- a/.gitignore +++ /dev/null @@ -1,52 +0,0 @@ -*.py[cod] - -# C extensions -*.so - -# Packages -*.egg -*.egg-info -dist -build -eggs -parts -bin -var -sdist -develop-eggs -.installed.cfg -lib -lib64 - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage -.tox -nosetests.xml -.testrepository - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# Complexity -output/*.html -output/*/index.html - -# Sphinx -doc/build - -# pbr generates these -AUTHORS -ChangeLog - -# Editors -*~ -.*.swp -.idea diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 335d142..0000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=stackforge/graffiti.git diff --git a/.mailmap b/.mailmap deleted file mode 100644 index cc92f17..0000000 --- a/.mailmap +++ /dev/null @@ -1,3 +0,0 @@ -# Format is: -# -# \ No newline at end of file diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index fb62267..0000000 --- a/.testr.conf +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ - ${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list \ No newline at end of file diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 6bf6814..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,16 +0,0 @@ -If you would like to contribute to the development of OpenStack, -you must follow the steps in this page: - - http://docs.openstack.org/infra/manual/developers.html - -Once those steps have been completed, changes to OpenStack -should be submitted for review via the Gerrit tool, following -the workflow documented at: - - http://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/graffiti \ No newline at end of file diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 5780a9f..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,4 +0,0 @@ -graffiti Style Commandments -=============================================== - -Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/ \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 67db858..0000000 --- a/LICENSE +++ /dev/null @@ -1,175 +0,0 @@ - - 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. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 90f8a7a..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -include AUTHORS -include ChangeLog -exclude .gitignore -exclude .gitreview - -global-exclude *.pyc \ No newline at end of file diff --git a/README.rst b/README.rst index 31073d3..9006052 100644 --- a/README.rst +++ b/README.rst @@ -1,13 +1,7 @@ -=============================== -graffiti -=============================== +This project is no longer maintained. -Cloud Capability Service +The contents of this repository are still available in the Git source code +management system. To see the contents of this repository before it reached +its end of life, please check out the previous commit with +"git checkout HEAD^1". -* Free software: Apache license -* Documentation: http://docs.openstack.org/developer/graffiti - -Features --------- - -* TODO \ No newline at end of file diff --git a/babel.cfg b/babel.cfg deleted file mode 100644 index efceab8..0000000 --- a/babel.cfg +++ /dev/null @@ -1 +0,0 @@ -[python: **.py] diff --git a/config.py b/config.py deleted file mode 100644 index e74c5d2..0000000 --- a/config.py +++ /dev/null @@ -1,156 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from oslo.config import cfg - -from graffiti.common import driver_factory -from graffiti.common import utils - -# Server Specific Configurations -server = { - 'port': '21075', - 'host': '0.0.0.0' -} - -# Pecan Application Configurations -app = { - 'root': 'graffiti.api.controllers.root.RootController', - 'modules': ['graffiti.api'], - 'static_root': '%(confdir)s/public', - 'template_path': '%(confdir)s/graffiti/templates', - 'debug': False, - 'errors': { - 404: '/error/404', - '__force_dict__': True - } -} - -logging = { - 'loggers': { - 'root': {'level': 'DEBUG', 'handlers': ['console']}, - 'graffiti': {'level': 'DEBUG', 'handlers': ['console']}, - 'wsme.api': {'level': 'DEBUG', 'handlers': ['console']}, - 'py.warnings': {'handlers': ['console']}, - '__force_dict__': True - }, - 'handlers': { - 'console': { - 'level': 'DEBUG', - 'class': 'logging.StreamHandler', - 'formatter': 'simple' - } - }, - 'formatters': { - 'simple': { - 'format': ('%(asctime)s %(levelname)-5.5s [%(name)s]' - '[%(threadName)s] %(message)s') - } - } -} - -wsme = { - 'debug': True -} - - -# Custom Configurations must be in Python dictionary format:: -# -# foo = {'bar':'baz'} -# -# All configurations are accessible at:: -# pecan.conf - -# oslo config -keystone_group = cfg.OptGroup('keystone') -keystone_opts = [ - cfg.StrOpt('auth_url', - default='http://127.0.0.1:5000/v2.0', - help='keystone authorization url'), - cfg.StrOpt('username', - default='admin', - help='keystone username'), - cfg.StrOpt('password', - default='secretword', - help='keystone password'), - cfg.StrOpt('tenant_name', - default='admin', - help='keystone tenant name') - -] -cfg.CONF.register_group(keystone_group) -cfg.CONF.register_opts(keystone_opts, group=keystone_group) - -# DEFAULT group -default_group = cfg.OptGroup('DEFAULT') -default_opts = [ - cfg.StrOpt( - 'persistence_type', - default="memory", - help=("persistence options. " - "values = 'memory' or 'file' or 'db")) -] - -cfg.CONF.register_group(default_group) -cfg.CONF.register_opts(default_opts, - group=default_group) - -# FILE_PERSISTENCE group -file_group = cfg.OptGroup('FILE_PERSISTENCE') -file_opts = [ - cfg.StrOpt( - 'dictionary_folder', - default="/tmp/graffiti-dictionary/", - help=("Absolute path of the file for persisting dictionary") - ) -] - -cfg.CONF.register_group(file_group) -cfg.CONF.register_opts(file_opts, - group=file_group) - - -# Used for remote debugging, like pychcharms or pydev -# To enable remote debugging in pycharms, requires that you put the -# pycharm-debug.egg in the python path. E.g. -# -# Include the pycharm-debug.egg archive. -# e.g. /home//pycharm-3.1.1/pycharm-debug.egg -# You can do it in a number of ways, for example: -# Add the archive to PYTHONPATH.e,g, -# export PYTHONPATH+=.:/home//pycharm-3.1.1/pycharm-debug.egg -# Append the archive to sys.path. e.g. -# import sys -# sys.path.append('/home//pycharm-3.1.1/pycharm-debug.egg') -# Just copy the pydev from the archive to the directory where your remote -# script resides. -# -# You will need to setup a debug configuration in your pycharms and start the -# debugger BEFORE starting pecan -# This is because the following code connects from here to your pycharms -# (or your pydev) -pydevd = { - 'enabled': False, - 'port': 22075, - 'bindhost': 'localhost' -} - - -# Discover and load drivers -df = driver_factory.DriverFactory() - -# Load Out of the box Dictionary -#specify url kwarg to load from URL. Or load from file system -utils.load_dictionary(url='http://localhost:21071/1/capability_type/all/') -#utils.load_dictionary() diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index 2061d43..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- coding: utf-8 -*- -# 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. - -import os -import sys - -sys.path.insert(0, os.path.abspath('../..')) -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - 'sphinx.ext.autodoc', - #'sphinx.ext.intersphinx', - 'oslo.sphinx' -] - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'graffiti' -copyright = u'2013, OpenStack Foundation' - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -# html_theme_path = ["."] -# html_theme = '_theme' -# html_static_path = ['static'] - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ('index', - '%s.tex' % project, - u'%s Documentation' % project, - u'OpenStack Foundation', 'manual'), -] - -# Example configuration for intersphinx: refer to the Python standard library. -#intersphinx_mapping = {'http://docs.python.org/': None} \ No newline at end of file diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst deleted file mode 100644 index 8cb3146..0000000 --- a/doc/source/contributing.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../CONTRIBUTING.rst \ No newline at end of file diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 377edc3..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. graffiti documentation master file, created by - sphinx-quickstart on Tue Jul 9 22:26:36 2013. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to graffiti's documentation! -======================================================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - readme - installation - usage - contributing - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/doc/source/installation.rst b/doc/source/installation.rst deleted file mode 100644 index 8322898..0000000 --- a/doc/source/installation.rst +++ /dev/null @@ -1,12 +0,0 @@ -============ -Installation -============ - -At the command line:: - - $ pip install graffiti - -Or, if you have virtualenvwrapper installed:: - - $ mkvirtualenv graffiti - $ pip install graffiti \ No newline at end of file diff --git a/doc/source/readme.rst b/doc/source/readme.rst deleted file mode 100644 index 6b2b3ec..0000000 --- a/doc/source/readme.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../README.rst \ No newline at end of file diff --git a/doc/source/usage.rst b/doc/source/usage.rst deleted file mode 100644 index 4a987e7..0000000 --- a/doc/source/usage.rst +++ /dev/null @@ -1,7 +0,0 @@ -======== -Usage -======== - -To use graffiti in a project:: - - import graffiti \ No newline at end of file diff --git a/etc/dictionary/CapabilityType-Samples.json b/etc/dictionary/CapabilityType-Samples.json deleted file mode 100644 index 186a320..0000000 --- a/etc/dictionary/CapabilityType-Samples.json +++ /dev/null @@ -1,196 +0,0 @@ -{ "capability_type_list" : -[ - { - "name": "Apache", - "namespace": "SAMPLES", - "description": "The Apache HTTP Server Project is a collaborative software development effort aimed at creating a robust, commercial-grade, featureful, and freely-available source code implementation of an HTTP (Web) server. The project is jointly managed by a group of volunteers located around the world, using the Internet and the Web to communicate, plan, and develop the server and its related documentation. This project is part of the Apache Software Foundation. In addition, hundreds of users have contributed ideas, code, and documentation to the project. This file is intended to briefly describe the history of the Apache HTTP Server and recognize the many contributors.", - "derived_from": { - "name": "Software", - "namespace": "SAMPLES" - }, - "properties": {} - }, - { - "name": "Database", - "namespace": "SAMPLES", - "description": "Database management systems (DBMSs) are specially designed software applications that interact with the user, other applications, and the database itself to capture and analyze data. A general-purpose DBMS is a software system designed to allow the definition, creation, querying, update, and administration of databases.", - "derived_from": { - "name": "Software", - "namespace": "SAMPLES" - }, - "properties": { - "listen_port": { - "type": "integer", - "description": "", - "required": false, - "confidential": false, - "minimum": 1, - "maximum": 65535 - } - } - }, - { - "name": "GPU", - "namespace": "SAMPLES", - "description": "", - "properties": {} - }, - { - "name": "LAMP", - "namespace": "SAMPLES", - "description": "", - "derived_from": { - "name": "SoftwareStack", - "namespace": "SAMPLES" - }, - "properties": {} - }, - { - "name": "MediaWiki", - "namespace": "SAMPLES", - "description": "", - "derived_from": { - "name": "Software", - "namespace": "SAMPLES" - }, - "properties": {} - }, - { - "name": "MongoDB", - "namespace": "SAMPLES", - "description": "", - "derived_from": { - "name": "BigData", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "MySQL", - "namespace": "SAMPLES", - "description": "", - "derived_from": { - "name": "Database", - "namespace": "SAMPLES" - }, - "properties": {} - }, - { - "name": "php", - "namespace": "SAMPLES", - "description": "", - "derived_from": { - "name": "Runtime", - "namespace": "SAMPLES" - }, - "properties": {} - }, - { - "name": "PropertyTypesSamples", - "namespace": "SAMPLES", - "description": "Sample Description", - "properties": { - "Property1": { - "type": "string", - "description": "Property1 blah", - "defaultValue": "BLAh", - "required": true, - "confidential": true, - "minLength": 1, - "maxLength": 45, - "pattern": "[A-Z]{3}.*" - }, - "Property2": { - "type": "integer", - "description": "Property2 blah", - "defaultValue": 4, - "required": false, - "confidential": false, - "minimum": 1, - "maximum": 6 - }, - "Property3": { - "type": "double", - "description": "Property3 blah", - "defaultValue": 4.5, - "required": false, - "confidential": false, - "minimum": 3, - "maximum": 7.64 - }, - "Property4": { - "type": "boolean", - "description": "Property4 blah", - "defaultValue": true, - "required": false, - "confidential": false - }, - "Property5": { - "type": "choice", - "description": "Property5 blah", - "required": false, - "confidential": false, - "itemType": "string", - "items": [ - "choice1", - "choice2", - "choice3" - ] - }, - "Property6": { - "type": "date", - "description": "Property6 blah", - "required": true, - "confidential": false - }, - "Property7": { - "type": "resource_id", - "description": "Property7 blah", - "required": false, - "confidential": false - }, - "Property8": { - "type": "string", - "description": "Property8 blah", - "required": true, - "confidential": false - } - } - }, - { - "name": "Runtime", - "namespace": "SAMPLES", - "description": "", - "derived_from": { - "name": "Software", - "namespace": "SAMPLES" - }, - "properties": {} - }, - { - "name": "Software", - "namespace": "SAMPLES", - "description": "", - "properties": { - "version": { - "type": "string", - "description": "", - "required": false, - "confidential": false - } - } - }, - { - "name": "SoftwareStack", - "namespace": "SAMPLES", - "description": "", - "properties": {} - }, - { - "name": "SSD", - "namespace": "SAMPLES", - "description": "SSD Drive", - "properties": {} - } -] -} \ No newline at end of file diff --git a/etc/dictionary/CapabilityType-os-compute-cpu.json b/etc/dictionary/CapabilityType-os-compute-cpu.json deleted file mode 100644 index 70cec55..0000000 --- a/etc/dictionary/CapabilityType-os-compute-cpu.json +++ /dev/null @@ -1,268 +0,0 @@ -{ "capability_type_list" : -[ - { - "name": "aes", - "namespace": "OS::COMPUTE::CPU", - "description": "CPU feature flag used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : features', ' 'lahf_lm'')", - "derived_from": { - "name": "features", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "features": { - "type": "string", - "description": "", - "defaultValue": "aes", - "required": true, - "confidential": false - } - } - }, - { - "name": "AMD", - "namespace": "OS::COMPUTE::CPU", - "description": "CPU vendor name used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : vendor', 'AMD')", - "derived_from": { - "name": "vendor", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "vendor": { - "type": "string", - "description": "", - "defaultValue": "AMD", - "required": true, - "confidential": false - } - } - }, - { - "name": "arch", - "namespace": "OS::COMPUTE::CPU", - "description": "", - "properties": {} - }, - { - "name": "Conroe", - "namespace": "OS::COMPUTE::CPU", - "description": "CPU model name used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : model', 'core2duo')", - "derived_from": { - "name": "model", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "model": { - "type": "string", - "description": "", - "defaultValue": "Conroe", - "required": true, - "confidential": false - } - } - }, - { - "name": "Core2duo", - "namespace": "OS::COMPUTE::CPU", - "description": "CPU model name used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : model', 'core2duo')", - "derived_from": { - "name": "model", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "model": { - "type": "string", - "description": "", - "defaultValue": "Core2duo", - "required": true, - "confidential": false - } - } - }, - { - "name": "cores", - "namespace": "OS::COMPUTE::CPU", - "description": "Number of cores used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : topology : cores', '1')", - "derived_from": { - "name": "topology", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "cores": { - "type": "integer", - "description": "", - "defaultValue": 1, - "required": true, - "confidential": false - } - } - }, - { - "name": "features", - "namespace": "OS::COMPUTE::CPU", - "description": "", - "properties": {} - }, - { - "name": "i686", - "namespace": "OS::COMPUTE::CPU", - "description": "CPU arch code used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : arch', 'x86_64')", - "derived_from": { - "name": "arch", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "arch": { - "type": "string", - "description": "", - "defaultValue": "i686", - "required": true, - "confidential": false - } - } - }, - { - "name": "Intel", - "namespace": "OS::COMPUTE::CPU", - "description": "CPU vendor name used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : vendor', 'Intel')", - "derived_from": { - "name": "vendor", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "vendor": { - "type": "string", - "description": "", - "defaultValue": "Intel", - "required": true, - "confidential": false - } - } - }, - { - "name": "mmx", - "namespace": "OS::COMPUTE::CPU", - "description": "CPU feature flag used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : features', ' 'lahf_lm'')", - "derived_from": { - "name": "features", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "features": { - "type": "string", - "description": "", - "defaultValue": "mmx", - "required": true, - "confidential": false - } - } - }, - { - "name": "model", - "namespace": "OS::COMPUTE::CPU", - "description": "", - "properties": {} - }, - { - "name": "rdtscp", - "namespace": "OS::COMPUTE::CPU", - "description": "CPU feature flag used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : features', ' 'lahf_lm'')", - "derived_from": { - "name": "features", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "features": { - "type": "string", - "description": "", - "defaultValue": "rdtscp", - "required": true, - "confidential": false - } - } - }, - { - "name": "sockets", - "namespace": "OS::COMPUTE::CPU", - "description": "Number of cores used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : topology : cores', '1')", - "derived_from": { - "name": "topology", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "sockets": { - "type": "integer", - "description": "", - "defaultValue": 1, - "required": true, - "confidential": false - } - } - }, - { - "name": "threads", - "namespace": "OS::COMPUTE::CPU", - "description": "Number of cores used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : topology : cores', '1')", - "derived_from": { - "name": "topology", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "threads": { - "type": "integer", - "description": "", - "defaultValue": 1, - "required": true, - "confidential": false - } - } - }, - { - "name": "topology", - "namespace": "OS::COMPUTE::CPU", - "description": "Number of cores used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : topology : cores', '1')", - "properties": {} - }, - { - "name": "vendor", - "namespace": "OS::COMPUTE::CPU", - "description": "", - "properties": {} - }, - { - "name": "Westmere", - "namespace": "OS::COMPUTE::CPU", - "description": "CPU model name used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : model', 'core2duo')", - "derived_from": { - "name": "model", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "model": { - "type": "string", - "description": "", - "defaultValue": "Westmere", - "required": true, - "confidential": false - } - } - }, - { - "name": "x86_64", - "namespace": "OS::COMPUTE::CPU", - "description": "CPU arch code used in ComputeCapabilitiesFilter matching extra_spec (k,v) = ('capabilities : cpu_info : arch', 'x86_64')", - "derived_from": { - "name": "arch", - "namespace": "OS::COMPUTE::CPU" - }, - "properties": { - "arch": { - "type": "string", - "description": "", - "defaultValue": "x86_64", - "required": true, - "confidential": false - } - } - } -] -} \ No newline at end of file diff --git a/etc/dictionary/CapabilityType-os-compute-guest.json b/etc/dictionary/CapabilityType-os-compute-guest.json deleted file mode 100644 index b2e1fd4..0000000 --- a/etc/dictionary/CapabilityType-os-compute-guest.json +++ /dev/null @@ -1,861 +0,0 @@ -{ "capability_type_list" : -[ - { - "name": "alpha", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "ArchLinux", - "namespace": "OS::COMPUTE::GUEST", - "description": "Arch Linux is a Linux-based operating system for i686 and x86-64 computers.It is composed predominantly of free and open source software, and supports community involvement.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "arch", - "required": false, - "confidential": false - } - } - }, - { - "name": "armv71", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "CENTOS", - "namespace": "OS::COMPUTE::GUEST", - "description": "Community Enterprise Operating System CentOS (abbreviated from Community Enterprise Operating System) is a Linux distribution that attempts to provide a free enterprise class computing platform which aims to be 100% binary compatible with its upstream source, Red Hat Enterprise Linux (RHEL).", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "centos", - "required": false, - "confidential": false - } - } - }, - { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose. The ImagePropertiesFilter filters compute nodes that satisfy any architecture, hypervisor type, or virtual machine mode properties specified on the instance's image properties. Image properties are contained in the image dictionary in the request_spec.", - "properties": {} - }, - { - "name": "cris", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "Debian", - "namespace": "OS::COMPUTE::GUEST", - "description": "Debian is an operating system composed of free software mostly carrying the GNU General Public License. The operating system is developed by an internet collaboration of volunteers aligned with The Debian Project. \n\nDebian systems can use either the Linux kernel (known as the Debian GNU/Linux distribution), the FreeBSD kernel (known as the Debian GNU/kFreeBSD distribution) or, more recently, the GNU Hurd kernel (more precisely, the GNU Mach microkernel and its servers; known as the Debian GNU/Hurd distribution).", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "debian", - "required": false, - "confidential": false - } - } - }, - { - "name": "Fedora", - "namespace": "OS::COMPUTE::GUEST", - "description": "Fedora (formerly Fedora Core) is an operating system based on the Linux kernel, developed by the community-supported Fedora Project and owned by Red Hat. Fedora contains software distributed under a free and open source license and aims to be on the leading edge of such technologies.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "fedora", - "required": false, - "confidential": false - } - } - }, - { - "name": "FreeBSD", - "namespace": "OS::COMPUTE::GUEST", - "description": "FreeBSD is a free Unix-like operating system descended from AT&T Unix via BSD. Although for legal reasons FreeBSD cannot be called \"Unix,\" it is a direct descendant from BSD, which was historically also called \"BSD Unix\" or \"Berkeley Unix.\"", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "freebsd", - "required": false, - "confidential": false - } - } - }, - { - "name": "GentooLinux", - "namespace": "OS::COMPUTE::GUEST", - "description": "Gentoo Linux is a computer operating system based on the Linux kernel and built using the Portage package management system. It is distributed as free and open source software. Unlike a binary software distribution, the source code is compiled locally according to the user's preferences and is often optimized for the specific type of computer. Precompiled binaries are available for some very large packages and for packages whose source code has not been released.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "gentoo", - "required": false, - "confidential": false - } - } - }, - { - "name": "i686", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "ia64", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "lm32", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "m68k", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "MandrakeLinux", - "namespace": "OS::COMPUTE::GUEST", - "description": "Mandriva Linux (result of fusion of the French distribution Mandrakelinux or Mandrake Linux and the Brazilian distribution Conectiva Linux) is a Linux distribution distributed by Mandriva. It uses the RPM Package Manager.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "mandrake", - "required": false, - "confidential": false - } - } - }, - { - "name": "MandrivaEnterpriseServer", - "namespace": "OS::COMPUTE::GUEST", - "description": "Mandriva Linux (result of fusion of the French distribution Mandrakelinux or Mandrake Linux and the Brazilian distribution Conectiva Linux) is a Linux distribution distributed by Mandriva. It uses the RPM Package Manager.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "mes", - "required": false, - "confidential": false - } - } - }, - { - "name": "MandrivaLinux", - "namespace": "OS::COMPUTE::GUEST", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "mandriva", - "required": false, - "confidential": false - } - } - }, - { - "name": "microblaze", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "microblazeel", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "mips", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "mips64", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "mips64el", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "mipsel", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "MS-DOS", - "namespace": "OS::COMPUTE::GUEST", - "description": "Microsoft Disc Operating System", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "msdos", - "required": false, - "confidential": false - } - } - }, - { - "name": "NetBSD", - "namespace": "OS::COMPUTE::GUEST", - "description": "NetBSD is an open-source Unix-like operating system descended from Berkeley Software Distribution (BSD), a Unix derivative developed at the University of California, Berkeley.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "netbsd", - "required": false, - "confidential": false - } - } - }, - { - "name": "OpenBSD", - "namespace": "OS::COMPUTE::GUEST", - "description": "OpenBSD is a Unix-like computer operating system descended from Berkeley Software Distribution (BSD), a Unix derivative developed at the University of California, Berkeley.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "openbsd", - "required": false, - "confidential": false - } - } - }, - { - "name": "openrisc", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "OpenSolaris", - "namespace": "OS::COMPUTE::GUEST", - "description": "OpenSolaris was an open source computer operating system based on Solaris created by Sun Microsystems. It was also the name of the project initiated by Sun to build a developer and user community around the software. After the acquisition of Sun Microsystems in 2010, Oracle decided to discontinue open development of the core software, and replaced the OpenSolaris distribution model with the proprietary Solaris Express.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "opensolaris", - "required": false, - "confidential": false - } - } - }, - { - "name": "OpenSUSE", - "namespace": "OS::COMPUTE::GUEST", - "description": "openSUSE is a general purpose operating system built on top of the Linux kernel, developed by the community-supported openSUSE Project and sponsored by SUSE and a number of other companies.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "opensuse", - "required": false, - "confidential": false - } - } - }, - { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST", - "description": "", - "properties": { - "os_version": { - "type": "string", - "description": "The operating system version as specified by the distributor (for example, 12.04).", - "required": false, - "confidential": false - } - } - }, - { - "name": "parisc", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "parisc64", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "ppc", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "ppc64", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "ppcemb", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "RedHatEnterpriseLinux", - "namespace": "OS::COMPUTE::GUEST", - "description": "Red Hat Enterprise Linux (RHEL) is a Linux distribution developed by Red Hat and targeted toward the commercial market.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "rhel", - "required": false, - "confidential": false - } - } - }, - { - "name": "s390", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "s390x", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "sh4", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "sh4eb", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "sparc", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "sparc64", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "SUSELinuxEnterpriseDesktop", - "namespace": "OS::COMPUTE::GUEST", - "description": "SUSE Linux Enterprise Desktop (SLED), formerly introduced as Novell Linux Desktop, is a Linux distribution supplied by SUSE and targeted at the business market. It is targeted for desktops.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "sled", - "required": false, - "confidential": false - } - } - }, - { - "name": "Ubuntu", - "namespace": "OS::COMPUTE::GUEST", - "description": "Ubuntu is a Debian-based Linux operating system.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "ubuntu", - "required": false, - "confidential": false - } - } - }, - { - "name": "unicore32", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - }, - { - "name": "Windows", - "namespace": "OS::COMPUTE::GUEST", - "description": "A series of graphical interface operating systems developed, marketed, and sold by Microsoft.", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "The common name of the operating system distribution in lowercase (uses the same data vocabulary as the libosinfo project).", - "defaultValue": "windows", - "required": false, - "confidential": false, - "pattern": "windows" - } - } - }, - { - "name": "x86_64", - "namespace": "OS::COMPUTE::GUEST", - "description": "Compute architecture. x86-64 (also known as x64, x86_64 and AMD64) is the 64-bit version of the x86 instruction set. It supports vastly larger amounts of virtual memory and physical memory than is possible on its predecessors, allowing programs to store larger amounts of data in memory. x86-64 also provides 64-bit general purpose registers and numerous other enhancements. The original specification was created by AMD, and has been implemented by AMD, Intel, VIA, and others. It is fully backwards compatible with 16-bit and 32-bit x86 code.", - "derived_from": { - "name": "CPUArchitecture", - "namespace": "OS::COMPUTE::GUEST" - }, - "properties": { - "architecture": { - "type": "string", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "defaultValue": "x86_64", - "required": false, - "confidential": false, - "pattern": "x86_64" - } - } - } -] -} \ No newline at end of file diff --git a/etc/dictionary/CapabilityType-os-compute-host.json b/etc/dictionary/CapabilityType-os-compute-host.json deleted file mode 100644 index 080899c..0000000 --- a/etc/dictionary/CapabilityType-os-compute-host.json +++ /dev/null @@ -1,354 +0,0 @@ -{ "capability_type_list" : -[ - { - "name": "ComputeDriverOptions", - "namespace": "OS::COMPUTE::HOST", - "description": "", - "properties": {} - }, - { - "name": "ContainerVirtualization", - "namespace": "OS::COMPUTE::HOST", - "description": "Executables in containers. This is the virtual machine mode (vm_mode) used by LXC. It may be used by the host properties filter for scheduling.", - "derived_from": { - "name": "VirtualizationMode", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "vm_mode": { - "type": "string", - "description": "", - "defaultValue": "exe", - "required": false, - "confidential": false, - "pattern": "exe" - } - } - }, - { - "name": "FullVirtualization", - "namespace": "OS::COMPUTE::HOST", - "description": "hvm Fully virtualized. This is the virtual machine mode (vm_mode) used by QEMU and KVM. It may be used by the host properties filter for scheduling.", - "derived_from": { - "name": "VirtualizationMode", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "vm_mode": { - "type": "string", - "description": "", - "defaultValue": "hvm", - "required": false, - "confidential": false, - "pattern": "hvm" - } - } - }, - { - "name": "HyperV", - "namespace": "OS::COMPUTE::HOST", - "description": "The hypervisor type (hypervisor_type). It may be used by the host properties filter for scheduling.", - "derived_from": { - "name": "HypervisorType", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "hypervisor_type": { - "type": "string", - "description": "", - "defaultValue": "hyperv", - "required": false, - "confidential": false, - "pattern": "hyperv" - } - } - }, - { - "name": "HypervisorType", - "namespace": "OS::COMPUTE::HOST", - "description": "The hypervisor type. It may be used by the host properties filter for scheduling. The ImagePropertiesFilter filters compute nodes that satisfy any architecture, hypervisor type, or virtual machine mode properties specified on the instance's image properties. Image properties are contained in the image dictionary in the request_spec.", - "properties": {} - }, - { - "name": "KVM", - "namespace": "OS::COMPUTE::HOST", - "description": "The hypervisor type (hypervisor_type). It may be used by the host properties filter for scheduling.", - "derived_from": { - "name": "HypervisorType", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "hypervisor_type": { - "type": "string", - "description": "", - "defaultValue": "kvm", - "required": false, - "confidential": false, - "pattern": "kvm" - } - } - }, - { - "name": "libvirtDriverOptions", - "namespace": "OS::COMPUTE::HOST", - "description": "The libvirt compute driver options. Sets hw_rng_model, hw_machine_type, hw_video_model, hw_video_ram, hw_watchdog_action, os_command_line properties.\n\nThese are properties specific to compute drivers. For a list of all hypervisors, see here: https://wiki.openstack.org/wiki/HypervisorSupportMatrix", - "derived_from": { - "name": "ComputeDriverOptions", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "hw_video_model": { - "type": "choice", - "description": "The video image driver used.", - "required": false, - "confidential": false, - "itemType": "string", - "items": [ - "vga", - "cirrus", - "vmvga", - "xen", - "gxl" - ] - }, - "hw_machine_type": { - "type": "string", - "description": "Enables booting an ARM system using the specified machine type. By default, if an ARM image is used and its type is not specified, Compute uses vexpress-a15 (for ARMv7) or virt (for AArch64) machine types.\n\nLibvirt machine type. Valid types can be viewed by using the virsh capabilities command (machine types are displayed in the machine tag).", - "required": false, - "confidential": false - }, - "hw_rng_model": { - "type": "string", - "description": "Adds a random-number generator device to the image's instances. The cloud administrator can enable and control device behavior by configuring the instance's flavor. By default, the generator device is disabled.", - "defaultValue": "virtio", - "required": false, - "confidential": false - }, - "hw_watchdog_action": { - "type": "choice", - "description": "Enables a virtual hardware watchdog device that carries out the specified action if the server hangs. The watchdog uses the i6300esb device (emulating a PCI Intel 6300ESB). If hw_watchdog_action is not specified, the watchdog is disabled.", - "defaultValue": "disabled", - "required": false, - "confidential": false, - "itemType": "string", - "items": [ - "disabled", - "reset", - "poweroff", - "pause", - "none" - ] - }, - "os_command_line": { - "type": "string", - "description": "The kernel command line to be used by the libvirt driver, instead of the default. For linux containers (LXC), the value is used as arguments for initialization.", - "required": false, - "confidential": false - } - } - }, - { - "name": "LXC", - "namespace": "OS::COMPUTE::HOST", - "description": "The hypervisor type (hypervisor_type). It may be used by the host properties filter for scheduling.", - "derived_from": { - "name": "HypervisorType", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "hypervisor_type": { - "type": "string", - "description": "", - "defaultValue": "lxc", - "required": false, - "confidential": false, - "pattern": "lxc" - } - } - }, - { - "name": "Qemu", - "namespace": "OS::COMPUTE::HOST", - "description": "The hypervisor type (hypervisor_type). It may be used by the host properties filter for scheduling.", - "derived_from": { - "name": "HypervisorType", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "hypervisor_type": { - "type": "string", - "description": "", - "defaultValue": "qemu", - "required": false, - "confidential": false, - "pattern": "qemu" - } - } - }, - { - "name": "UserModeLinux-UML", - "namespace": "OS::COMPUTE::HOST", - "description": "The uml hypervisor type (hypervisor_type). It may be used by the host properties filter for scheduling.", - "derived_from": { - "name": "HypervisorType", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "hypervisor_type": { - "type": "string", - "description": "", - "defaultValue": "uml", - "required": false, - "confidential": false, - "pattern": "uml" - } - } - }, - { - "name": "UserModeLinuxParavirtualization", - "namespace": "OS::COMPUTE::HOST", - "description": "uml�User Mode Linux paravirtualized virtual machine mode (vm_mode). It may be used by the host properties filter for scheduling.", - "derived_from": { - "name": "VirtualizationMode", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "vm_mode": { - "type": "string", - "description": "", - "defaultValue": "uml", - "required": false, - "confidential": false, - "pattern": "uml" - } - } - }, - { - "name": "VirtualizationMode", - "namespace": "OS::COMPUTE::HOST", - "description": "The virtual machine mode. This represents the host/guest ABI (application binary interface) used for the virtual machine. The ImagePropertiesFilter filters compute nodes that satisfy any architecture, hypervisor type, or virtual machine mode properties specified on the instance's image properties. Image properties are contained in the image dictionary in the request_spec.", - "properties": {} - }, - { - "name": "VMWare", - "namespace": "OS::COMPUTE::HOST", - "description": "The hypervisor type (hypervisor_type). It may be used by the host properties filter for scheduling.", - "derived_from": { - "name": "HypervisorType", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "hypervisor_type": { - "type": "string", - "description": "", - "defaultValue": "vmware", - "required": false, - "confidential": false, - "pattern": "vmware" - } - } - }, - { - "name": "VMwareDriverOptions", - "namespace": "OS::COMPUTE::HOST", - "description": "The VMWare compute driver. Sets vmware_adaptertype, vmware_ostype, vmware_image_version properties.\n\nThese are properties specific to compute drivers. For a list of all hypervisors, see here: https://wiki.openstack.org/wiki/HypervisorSupportMatrix", - "derived_from": { - "name": "ComputeDriverOptions", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "vmware_adaptertype": { - "type": "choice", - "description": "Indicates the virtual SCSI or IDE controller used by the hypervisor.", - "required": false, - "confidential": false, - "itemType": "string", - "items": [ - "lsiLogic", - " busLogic", - "ide" - ] - }, - "vmware_ostype": { - "type": "string", - "description": "A VMware GuestID which describes the operating system installed in the image. This will be passed to the hypervisor when creating a virtual machine. See thinkvirt.com for a list of valid values. If this is not specified, it will default to otherGuest.", - "required": false, - "confidential": false - }, - "vmware_image_version": { - "type": "string", - "description": "Currently unused, set it to 1.", - "defaultValue": "1", - "required": false, - "confidential": false - } - } - }, - { - "name": "Xen", - "namespace": "OS::COMPUTE::HOST", - "description": "The hypervisor type (hypervisor_type). It may be used by the host properties filter for scheduling.", - "derived_from": { - "name": "HypervisorType", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "hypervisor_type": { - "type": "string", - "description": "", - "defaultValue": "xen", - "required": false, - "confidential": false, - "pattern": "xen" - } - } - }, - { - "name": "XenDriverOptions", - "namespace": "OS::COMPUTE::HOST", - "description": "The XenAPI Driver. Sets auto_disk_config and os_type.\n\nThese are properties specific to compute drivers. For a list of all hypervisors, see here: https://wiki.openstack.org/wiki/HypervisorSupportMatrix", - "derived_from": { - "name": "ComputeDriverOptions", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "auto_disk_config": { - "type": "boolean", - "description": "If true, the root partition on the disk is automatically resized before the instance boots. This value is only taken into account by the Compute service when using a Xen-based hypervisor with the XenAPI driver. The Compute service will only attempt to resize if there is a single partition on the image, and only if the partition is in ext3 or ext4 format.", - "required": false, - "confidential": false - }, - "os_type": { - "type": "choice", - "description": "The operating system installed on the image. The XenAPI driver contains logic that takes different actions depending on the value of the os_type parameter of the image. For example, for os_type=windows images, it creates a FAT32-based swap partition instead of a Linux swap partition, and it limits the injected host name to less than 16 characters.", - "required": false, - "confidential": false, - "itemType": "string", - "items": [ - "linux", - "windows" - ] - } - } - }, - { - "name": "XenParavirtualization", - "namespace": "OS::COMPUTE::HOST", - "description": "xen�Xen 3.0 paravirtualized virtual machine mode (vm_mode). It may be used by the host properties filter for scheduling.", - "derived_from": { - "name": "VirtualizationMode", - "namespace": "OS::COMPUTE::HOST" - }, - "properties": { - "vm_mode": { - "type": "string", - "description": "", - "defaultValue": "xen", - "required": false, - "confidential": false, - "pattern": "xen" - } - } - } -] -} \ No newline at end of file diff --git a/etc/dictionary/CapabilityType-os-glance.json b/etc/dictionary/CapabilityType-os-glance.json deleted file mode 100644 index 830e490..0000000 --- a/etc/dictionary/CapabilityType-os-glance.json +++ /dev/null @@ -1,45 +0,0 @@ -{ "capability_type_list" : -[ - { - "name": "Image", - "namespace": "OS::GLANCE", - "description": "A collection of files for a specific operating system (OS) that you use to create or rebuild a server. OpenStack provides pre-built images. You can also create custom images, or snapshots, from servers that you have launched. Custom images can be used for data backups or as \"gold\" images for additional servers.", - "properties": {} - }, - { - "name": "ImageSnapshot", - "namespace": "OS::GLANCE", - "description": "The OpenStack snapshot mechanism allows you to create new images from running instances. This is very convenient for upgrading base images or for taking a published image and customizing it for local use. However, an instance snapshot is an image. The only difference between an image that you upload directly to the Image Service and an image that you create by snapshot is that an image created by snapshot has additional properties in the glance database.", - "properties": { - "image_type": { - "type": "string", - "description": "", - "defaultValue": "snapshot", - "required": false, - "confidential": false, - "pattern": "snapshot" - }, - "instance_uuid": { - "type": "string", - "description": "uuid of instance that was snapshotted", - "required": false, - "confidential": false - }, - "base_image_ref": { - "type": "string", - "description": "uuid of original image of instance that was snapshotted", - "required": false, - "confidential": false - }, - "image_location": { - "type": "string", - "description": "", - "defaultValue": "snapshot", - "required": false, - "confidential": false, - "pattern": "snapshot" - } - } - } -] -} \ No newline at end of file diff --git a/etc/dictionary/CapabilityType-trust.json b/etc/dictionary/CapabilityType-trust.json deleted file mode 100644 index dbee6a3..0000000 --- a/etc/dictionary/CapabilityType-trust.json +++ /dev/null @@ -1,43 +0,0 @@ -{ "capability_type_list" : -[ - { - "name": "BIOSTXT", - "namespace": "TRUST", - "description": "BIOS Trusted Execution Technology", - "derived_from": { - "name": "Trusted", - "namespace": "TRUST" - }, - "properties": { - "enabled": { - "type": "boolean", - "description": "", - "required": false, - "confidential": false - }, - "verified": { - "type": "boolean", - "description": "", - "required": false, - "confidential": false - } - } - }, - { - "name": "HypervisorTXT", - "namespace": "TRUST", - "description": "Hypervisor Trusted Execution Technology", - "derived_from": { - "name": "Trusted", - "namespace": "TRUST" - }, - "properties": {} - }, - { - "name": "Trusted", - "namespace": "TRUST", - "description": "", - "properties": {} - } -] -} \ No newline at end of file diff --git a/etc/dictionary/CapabilityType_ApplicationDevelopment.json b/etc/dictionary/CapabilityType_ApplicationDevelopment.json deleted file mode 100644 index db127b3..0000000 --- a/etc/dictionary/CapabilityType_ApplicationDevelopment.json +++ /dev/null @@ -1,252 +0,0 @@ -{ "capability_type_list" : -[ - { - "name": "ApplicationDevelopment", - "namespace": "APPLICATION::CATEGORIES", - "description": "Application Development", - "derived_from": { - "name": "SoftwareInfrastructure", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "ApplicationServers", - "namespace": "APPLICATION::CATEGORIES", - "description": "Application Servers", - "derived_from": { - "name": "SoftwareInfrastructure", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "ApplicationStacks", - "namespace": "APPLICATION::CATEGORIES", - "description": "Application Stacks", - "derived_from": { - "name": "SoftwareInfrastructure", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "BigData", - "namespace": "APPLICATION::CATEGORIES", - "description": "Big Data", - "derived_from": { - "name": "SoftwareInfrastructure", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "BusinessIntelligence", - "namespace": "APPLICATION::CATEGORIES", - "description": "Business Intelligence", - "derived_from": { - "name": "BusinessSoftware", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "BusinessSoftware", - "namespace": "APPLICATION::CATEGORIES", - "description": "Business Software", - "properties": {} - }, - { - "name": "Collaboration", - "namespace": "APPLICATION::CATEGORIES", - "description": "Collaboration", - "derived_from": { - "name": "BusinessSoftware", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "ContentManagement", - "namespace": "APPLICATION::CATEGORIES", - "description": "Content Management", - "derived_from": { - "name": "BusinessSoftware", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "CRM", - "namespace": "APPLICATION::CATEGORIES", - "description": "CRM", - "derived_from": { - "name": "BusinessSoftware", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "DatabasesAndCaching", - "namespace": "APPLICATION::CATEGORIES", - "description": "Databases & Caching", - "derived_from": { - "name": "SoftwareInfrastructure", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "DeveloperTools", - "namespace": "APPLICATION::CATEGORIES", - "description": "Developer Tools", - "properties": {} - }, - { - "name": "eCommerce", - "namespace": "APPLICATION::CATEGORIES", - "description": "eCommerce", - "derived_from": { - "name": "BusinessSoftware", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "FinancialServices", - "namespace": "APPLICATION::CATEGORIES", - "description": "Financial Services", - "derived_from": { - "name": "BusinessSoftware", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "HighPerformanceComputing", - "namespace": "APPLICATION::CATEGORIES", - "description": "High Performance Computing", - "derived_from": { - "name": "BusinessSoftware", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "IssuesAndBugTracking", - "namespace": "APPLICATION::CATEGORIES", - "description": "Issue & Bug Tracking", - "derived_from": { - "name": "DeveloperTools", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "LogAnalysis", - "namespace": "APPLICATION::CATEGORIES", - "description": "Log Analysis", - "derived_from": { - "name": "DeveloperTools", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "Media", - "namespace": "APPLICATION::CATEGORIES", - "description": "Media", - "derived_from": { - "name": "BusinessSoftware", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "Monitoring", - "namespace": "APPLICATION::CATEGORIES", - "description": "Monitoring", - "derived_from": { - "name": "DeveloperTools", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "NetworkInfrastructure", - "namespace": "APPLICATION::CATEGORIES", - "description": "Network Infrastructure", - "derived_from": { - "name": "SoftwareInfrastructure", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "OperatingSystems", - "namespace": "APPLICATION::CATEGORIES", - "description": "Operating Systems", - "derived_from": { - "name": "SoftwareInfrastructure", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "ProjectManagement", - "namespace": "APPLICATION::CATEGORIES", - "description": "Project Management", - "derived_from": { - "name": "BusinessSoftware", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "Security", - "namespace": "APPLICATION::CATEGORIES", - "description": "Security", - "derived_from": { - "name": "SoftwareInfrastructure", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "SoftwareInfrastructure", - "namespace": "APPLICATION::CATEGORIES", - "description": "Software Infrastructure", - "properties": {} - }, - { - "name": "SourceControl", - "namespace": "APPLICATION::CATEGORIES", - "description": "Source Control", - "derived_from": { - "name": "DeveloperTools", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "StorageAndBackup", - "namespace": "APPLICATION::CATEGORIES", - "description": "Storage & Backup", - "derived_from": { - "name": "BusinessSoftware", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - }, - { - "name": "Testing", - "namespace": "APPLICATION::CATEGORIES", - "description": "Testing", - "derived_from": { - "name": "DeveloperTools", - "namespace": "APPLICATION::CATEGORIES" - }, - "properties": {} - } -] -} \ No newline at end of file diff --git a/etc/dictionary/Namespaces.json b/etc/dictionary/Namespaces.json deleted file mode 100644 index 27e2190..0000000 --- a/etc/dictionary/Namespaces.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "namespace": "APPLICATION::CATEGORIES", - "resource_types": [ "OS::GLANCE::IMAGE", "OS::GLANCE::SNAPSHOT", "OS::CINDER::VOLUME", "OS::CINDER::VOLUMESNAPSHOT" ], - "property_format" : "P" - }, - { - "namespace": "OS::CINDER", - "resource_types": [ "OS::GLANCE::IMAGE", "OS::GLANCE::SNAPSHOT", "OS::CINDER::VOLUME", "OS::CINDER::VOLUMESNAPSHOT" ], - "property_format" : "P" - }, - { - "namespace": "OS::COMPUTE::CPU", - "resource_types": [ "OS::GLANCE::IMAGE", "OS::GLANCE::SNAPSHOT", "OS::CINDER::VOLUME", "OS::CINDER::VOLUMESNAPSHOT" ], - "property_format" : "P" - }, - { - "namespace": "SAMPLES", - "resource_types": [ "OS::GLANCE::IMAGE", "OS::GLANCE::SNAPSHOT", "OS::CINDER::VOLUME", "OS::CINDER::VOLUMESNAPSHOT" ], - "property_format" : "P" - }, - { - "namespace": "OS::COMPUTE::HOST", - "resource_types": [ "OS::GLANCE::IMAGE", "OS::GLANCE::SNAPSHOT", "OS::CINDER::VOLUME", "OS::CINDER::VOLUMESNAPSHOT" ], - "property_format" : "P" - }, - { - "namespace": "OS::COMPUTE::GUEST", - "resource_types": [ "OS::GLANCE::IMAGE", "OS::GLANCE::SNAPSHOT", "OS::CINDER::VOLUME", "OS::CINDER::VOLUMESNAPSHOT" ], - "property_format" : "P" - }, - { - "namespace": "OS::COMPUTE", - "resource_types": [ "OS::GLANCE::IMAGE", "OS::GLANCE::SNAPSHOT", "OS::CINDER::VOLUME", "OS::CINDER::VOLUMESNAPSHOT" ], - "property_format" : "P" - }, - { - "namespace": "SERVICE::ASSURANCE", - "resource_types": [ "OS::NOVA::FLAVOR", "OS::NOVA::HOSTAGGREGATE" ], - "property_format" : "P" - } -] \ No newline at end of file diff --git a/etc/graffiti.conf.sample b/etc/graffiti.conf.sample deleted file mode 100644 index f94a41d..0000000 --- a/etc/graffiti.conf.sample +++ /dev/null @@ -1,11 +0,0 @@ -[DEFAULT] - -#Allowed values= memory, file, db. Default value is memory -persistence_type=memory - -[FILE_PERSISTENCE] -dictionary_folder=/tmp/graffiti-dictionary/ - -[DATABASE] -#connection = sqlite:////var/tmp/graffiti.db -#connection = mysql://graffiti:graffiti@127.0.0.1:3306/graffiti diff --git a/etc/temp-token.txt b/etc/temp-token.txt deleted file mode 100644 index 08b55f2..0000000 --- a/etc/temp-token.txt +++ /dev/null @@ -1 +0,0 @@ -{ "id": "12341234123412341234123412341234", "user_id": "12341234123412341234123412341234", "project_id": "12341234123412341234123412341234","domain_id": "12341234123412341234123412341234","roles": ["admin"] } \ No newline at end of file diff --git a/graffiti/__init__.py b/graffiti/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/api/__init__.py b/graffiti/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/api/app.py b/graffiti/api/app.py deleted file mode 100644 index 515b3d6..0000000 --- a/graffiti/api/app.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from pecan import make_app - -from graffiti.api import model -from graffiti.api.service import prepare_service - -from graffiti.api.hooks import CorsHook - -from oslo.config import cfg -CONF = cfg.CONF - - -def setup_app(config): - - if hasattr(config, 'pydevd') and config.pydevd.enabled: - try: - print( - 'Remote debug set to true(config.pydevd). ' - 'Attempting connection' - ) - import pydevd - pydevd.settrace( - config.pydevd.bindhost, - port=config.pydevd.port, - stdoutToServer=True, - stderrToServer=True, - suspend=False) - except BaseException as be: - print "Debug Connection Error (Ignoring): %s" % be - - model.init_model() - app_conf = dict(config.app) - - prepare_service() - - app_hooks = [CorsHook()] - - return make_app( - app_conf.pop('root'), - logging=getattr(config, 'logging', {}), - hooks=app_hooks, - **app_conf - ) diff --git a/graffiti/api/controllers/__init__.py b/graffiti/api/controllers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/api/controllers/root.py b/graffiti/api/controllers/root.py deleted file mode 100644 index 673dfb4..0000000 --- a/graffiti/api/controllers/root.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from pecan import expose -from webob.exc import status_map - -from graffiti.api.controllers.versions import V1Controller - - -class RootController(object): - - v1 = V1Controller() - - @expose('error.html') - def error(self, status): - try: - status = int(status) - except ValueError: # pragma: no cover - status = 500 - message = getattr(status_map.get(status), 'explanation', '') - return dict(status=status, message=message) diff --git a/graffiti/api/controllers/v1/__init__.py b/graffiti/api/controllers/v1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/api/controllers/v1/capability_type.py b/graffiti/api/controllers/v1/capability_type.py deleted file mode 100644 index 9c7c3bd..0000000 --- a/graffiti/api/controllers/v1/capability_type.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from pecan.rest import RestController - -from wsme.api import Response -from wsmeext.pecan import wsexpose - -from graffiti.api.controllers.v1.capability_type_batch import\ - CapabilityTypeBatchController -from graffiti.api.controllers.v1.capability_type_derived import\ - CapabilityTypeDerivedController -from graffiti.api.model.v1.capability_type import CapabilityType -from graffiti.api.model.v1.dao.captype_dao_factory \ - import CapabilityTypeDAOFactory -from graffiti.api.model.v1.dao.ns_dao_factory import NSDAOFactory -from oslo.config import cfg - - -import six - - -class CapabilityTypeController(RestController): - - batch = CapabilityTypeBatchController() - derived_properties = CapabilityTypeDerivedController() - - def __init__(self): - super(RestController, self).__init__() - self.status = 200 - self._cap_controller = None - self._ns_controller = None - self._load_controller() - - def _load_controller(self): - dao_type = cfg.CONF.DEFAULT.persistence_type - self._cap_controller = CapabilityTypeDAOFactory.create(dao_type) - self._ns_controller = NSDAOFactory.get() - - @wsexpose - def options(): - pass - - @wsexpose(CapabilityType, six.text_type, six.text_type) - def get_one(self, name, namespace): - captype = self._cap_controller.get_capability_type(name, namespace) - return captype - - @wsexpose([CapabilityType], six.text_type) - def get_all(self, query_string=None): - captype_list = self._cap_controller.find_capability_types(query_string) - return captype_list - - @wsexpose(CapabilityType, body=CapabilityType) - def post(self, capability_type): - """Create Capability Type - @type capability_type: - graffiti.api.model.v1.capability_type.CapabilityType - @param capability_type: Capability type - """ - - # Check if namespace exists - namespace_found = self.__check_existing_namespace( - capability_type.namespace - ) - - # Check if derived capability type exists - derived_checked = self.__check_derived_capability( - capability_type.derived_from - ) - - if namespace_found and derived_checked: - self._cap_controller.set_capability_type( - capability_type - ) - return capability_type - else: - res = Response( - CapabilityType(), - status_code=404, - error="Provided namespace %s doesnt exist" % - capability_type.namespace) - return res - - @wsexpose(CapabilityType, six.text_type, six.text_type, - body=CapabilityType) - def put(self, name, namespace, capability_type): - - # Check if namespace exists - namespace_found = self.__check_existing_namespace( - capability_type.namespace - ) - - # Check if derived capability type exists - derived_checked = self.__check_derived_capability( - capability_type.derived_from - ) - - if namespace_found and derived_checked: - self._cap_controller.put_capability_type( - name, namespace, capability_type - ) - return capability_type - else: - res = Response( - CapabilityType(), - status_code=404, - error="Provided namespace %s doesnt exist" % - capability_type.namespace) - return res - - @wsexpose(CapabilityType, six.text_type, six.text_type) - def delete(self, name, namespace): - captype = self._cap_controller.delete_capability_type( - name, - namespace - ) - return captype - - def __check_derived_capability(self, derived_from): - derived_checked = True - if derived_from: - derived_checked = False - derived_cap_found = self._cap_controller.get_capability_type( - derived_from.name, derived_from.namespace) - if derived_cap_found: - derived_checked = True - - return derived_checked - - def __check_existing_namespace(self, namespace_name): - return self._ns_controller.get_namespace(namespace_name) diff --git a/graffiti/api/controllers/v1/capability_type_batch.py b/graffiti/api/controllers/v1/capability_type_batch.py deleted file mode 100644 index 621cfed..0000000 --- a/graffiti/api/controllers/v1/capability_type_batch.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -from graffiti.api.model.v1.capability_type import CapabilityType -from graffiti.api.model.v1.dao.captype_dao_factory \ - import CapabilityTypeDAOFactory -from graffiti.api.model.v1.dao.ns_dao_factory import NSDAOFactory - -from graffiti.common import exception as exc -from graffiti.common.utilities.capability_type_tree import CapabilityTypeTree - -from oslo.config import cfg -from pecan.rest import RestController -from wsmeext.pecan import wsexpose - - -class CapabilityTypeBatchController(RestController): - def __init__(self): - super(RestController, self).__init__() - self.status = 200 - self._cap_controller = None - self._ns_controller = None - self._load_controller() - - def _load_controller(self): - dao_type = cfg.CONF.DEFAULT.persistence_type - self._cap_controller = CapabilityTypeDAOFactory.create(dao_type) - self._ns_controller = NSDAOFactory.get() - - @wsexpose - def options(self): - pass - - @wsexpose([CapabilityType], body=[CapabilityType]) - def post(self, capability_types): - """Batch create capability types - @param capability_types: list of CapabilityTypes - """ - - cap_types = [] - # Verify all namespaces exists - self.__verify_namespaces(capability_types) - - tree = CapabilityTypeTree() - tree.build(capability_types) - - # TODO(wko): verify external derived roots - # self.__verify_external_derived_roots_exist( - # tree.types_with_external_root) - - for cap_key, cap_node in tree.root_types.iteritems(): - self.create_capability_type_recursively(cap_node, cap_types) - - return cap_types - - def create_capability_type_recursively(self, tree_node, cap_types): - if tree_node: - capability_type = tree_node.cap_type - exists_ct = self._cap_controller.get_capability_type( - capability_type.name, capability_type.namespace) - - if exists_ct: - # update - self._cap_controller.put_capability_type( - capability_type.name, capability_type.namespace, - capability_type - ) - cap_types.append(capability_type) - else: - # add - new_ct = self._cap_controller.set_capability_type( - capability_type) - cap_types.append(new_ct) - - for cap_key, child_node in tree_node.children.iteritems(): - self.create_capability_type_recursively(child_node, cap_types) - - def __verify_namespaces(self, capability_types): - namespaces = [] - for ct in capability_types: - if ct.namespace not in namespaces: - namespaces.append(ct.namespace) - - found_namespace = False - for namespace in namespaces: - found_namespace = self._ns_controller.get_namespace(namespace) - if not found_namespace: - raise exc.NotFound("namespace:{0} - does not exist". - format(namespace)) diff --git a/graffiti/api/controllers/v1/capability_type_derived.py b/graffiti/api/controllers/v1/capability_type_derived.py deleted file mode 100644 index 4a7858e..0000000 --- a/graffiti/api/controllers/v1/capability_type_derived.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from pecan.rest import RestController - -from wsmeext.pecan import wsexpose - -from graffiti.api.model.v1.capability_type_derived_prop import \ - CapabilityTypeDerivedProperties -from graffiti.api.model.v1.dao.captype_dao_factory \ - import CapabilityTypeDAOFactory -from oslo.config import cfg - - -import six - - -class CapabilityTypeDerivedController(RestController): - - def __init__(self): - super(RestController, self).__init__() - self.status = 200 - self._cap_controller = None - self._load_controller() - - def _load_controller(self): - dao_type = cfg.CONF.DEFAULT.persistence_type - self._cap_controller = CapabilityTypeDAOFactory.create(dao_type) - - @wsexpose - def options(): - pass - - @wsexpose(CapabilityTypeDerivedProperties, six.text_type, six.text_type) - def get_one(self, name, namespace): - captype = self._cap_controller.\ - get_capability_type_with_derived_properties(name, namespace) - return captype diff --git a/graffiti/api/controllers/v1/namespace.py b/graffiti/api/controllers/v1/namespace.py deleted file mode 100644 index b303edd..0000000 --- a/graffiti/api/controllers/v1/namespace.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from pecan.rest import RestController - -from wsmeext.pecan import wsexpose - -from graffiti.api.model.v1.dao.ns_dao_factory \ - import NSDAOFactory -from graffiti.api.model.v1.namespace import Namespace -from oslo.config import cfg -import six - - -class NamespaceController(RestController): - def __init__(self): - super(RestController, self).__init__() - self.status = 200 - self._controller = self._load_controller() - - def _load_controller(self): - controller_type = cfg.CONF.DEFAULT.persistence_type - _controller = NSDAOFactory.create(controller_type) - return _controller - - @wsexpose - def options(self): - pass - - @wsexpose(Namespace, six.text_type) - def get_one(self, namespace_name): - namespace = self._controller.get_namespace(namespace_name) - return namespace - - @wsexpose([Namespace]) - def get_all(self, query_string=None): - namespace_list = self._controller.find_namespaces(query_string) - return namespace_list - - @wsexpose(Namespace, body=Namespace) - def post(self, namespace): - """Create Namespace - :namespace param: - graffiti.api.model.v1.namespace.Namespace - """ - - self._controller.set_namespace(namespace) - return namespace - - @wsexpose(Namespace, six.text_type, body=Namespace) - def put(self, namespace_name, namespace): - self._controller.put_namespace(namespace_name, namespace) - return namespace - - @wsexpose(Namespace, six.text_type) - def delete(self, namespace_name): - print "namespace", namespace_name - namespace = self._controller.delete_namespace(namespace_name) - return namespace diff --git a/graffiti/api/controllers/v1/resource.py b/graffiti/api/controllers/v1/resource.py deleted file mode 100644 index c8593ae..0000000 --- a/graffiti/api/controllers/v1/resource.py +++ /dev/null @@ -1,229 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import json - -import pecan -from pecan.rest import RestController - - -from wsme.api import Response -from wsme.rest.json import fromjson -from wsmeext.pecan import wsexpose - - -from graffiti.api.model.v1.resource import Resource -from graffiti.api.model.v1.resource_query import ResourceQuery -from graffiti.common import driver_factory -from graffiti.common.exception import DriverNotFound -from graffiti.common.exception import DriverNotFoundForResourceType - -import six - - -class ResourceController(RestController): - - def __init__(self): - super(ResourceController, self).__init__() - self.status = 200 - self.default_resource_type = "GFT::Local" - - @wsexpose(None, six.text_type, six.text_type, six.text_type) - def options(self, param1, param2=None, param3=None): - return Response(None, status_code=204) - - @wsexpose(Resource, six.text_type, six.text_type, six.text_type) - def get_one(self, param1, param2=None, param3=None): - """Retrieve the resource based on the passed parameters - Depending on the number of parameters passed, the meaning - of the parameter is determined. - - Use case #1: only param1 is set - eg. /v1/resource/12345 - param1 is treated as resource id and resource type is defaulted - to graffiti local resource - - Use case #2: param1 and param2 are set - eg /v1/resource/OS::Glance::Image/d24a33343 - param1 = resource type - param2 = resource id - - Use case #3: param1, param2 and param3 are set - eg /v1/resource/OS::Glance::Image/d24a33343/e8dd383a838c83 - param1 = resource type - param2 = resource id - param3 = endpoint id - - """ - print "args:", param1, param2, param3 - auth_token = pecan.request.headers.get('X-Auth-Token') - endpoint_id = None - - if not param2: - #Use case #1 - resource_id = param1 - resource_type = self.default_resource_type - else: - #Use case #2 - resource_type = param1 - resource_id = param2 - - if param3: - endpoint_id = param3 - - driver = driver_factory.get_driver(resource_type) - if driver.resource: - res = driver.resource.get_resource( - resource_type, - resource_id, - auth_token, - endpoint_id - ) - return res - else: - error_str = "Driver not found for the resource type %s", \ - resource_type - - res = Response(Resource(), status_code=404, error=error_str) - return res - - @wsexpose([Resource], six.text_type, six.text_type) - def get_all(self, resource_type=None, query_string=None): - print "args: resource_type=%s, query_string=%s" % \ - (resource_type, query_string) - auth_token = pecan.request.headers.get('X-Auth-Token') - - resource_types = [] - if query_string: - doc = json.loads(query_string) - resource_query = fromjson(ResourceQuery, doc) - resource_types = resource_query.resource_types - else: - if not resource_type: - resource_types.append(self.default_resource_type) - else: - resource_types.append(resource_type) - - driver_resources = ResourceController.__group_resource_types_by_driver( - driver_factory.get_resource_types(), - resource_types - ) - - all_resource_list = [] - for driver_name in driver_resources.keys(): - req_resource_types = driver_resources[driver_name] - resource_query = ResourceQuery() - resource_query.resource_types = req_resource_types - try: - print "Invoking driver(%s) for resource types(%s):" % \ - (driver_name, req_resource_types) - driver = driver_factory.get_driver_by_name(driver_name) - except DriverNotFound: - resource = Response( - Resource(), - status_code=404, - error="Driver not found for the resource type") - return resource - - if driver.resource: - res_list = driver.resource.find_resources( - resource_query, - auth_token - ) - if res_list: - all_resource_list += res_list.values() - - if all_resource_list: - return all_resource_list - - return [] - - @wsexpose(Resource, six.text_type, body=Resource) - def put(self, resource_id, resource): - """Modify resource - :resource param: graffiti.api.model.v1.resource.Resource - """ - - auth_token = pecan.request.headers.get('X-Auth-Token') - endpoint_id = resource.provider.id - - if not resource.type: - resource_type = self.default_resource_type - else: - resource_type = resource.type - - driver = driver_factory.get_driver(resource_type) - if driver.resource: - driver.resource.update_resource( - resource_type, - resource_id, - resource, - auth_token, - endpoint_id=endpoint_id - ) - else: - resource = Response( - Resource(), - status_code=404, - error="Driver not found for the resource type" - ) - - return resource - - @wsexpose(Resource, body=Resource) - def post(self, resource): - auth_token = pecan.request.headers.get('X-Auth-Token') - - if not resource.type: - resource_type = self.default_resource_type - else: - resource_type = resource.type - - driver = driver_factory.get_driver(resource_type) - if driver.resource: - resource = driver.resource.create_resource( - resource_type, - resource, - auth_token - ) - - return resource - - @staticmethod - def __group_resource_types_by_driver( - all_resource_types, - request_resource_types): - driver_resource_types = dict() - for resource_type in request_resource_types: - - if resource_type in all_resource_types.keys(): - driver_name = all_resource_types[resource_type] - else: - raise DriverNotFoundForResourceType( - resource_type=resource_type - ) - - resource_list = [] - if driver_name in driver_resource_types.keys(): - resource_list = driver_resource_types[driver_name] - if not resource_list: - resource_list = [] - resource_list.append(resource_type) - driver_resource_types[driver_name] = resource_list - else: - resource_list.append(resource_type) - driver_resource_types[driver_name] = resource_list - - return driver_resource_types diff --git a/graffiti/api/controllers/versions.py b/graffiti/api/controllers/versions.py deleted file mode 100644 index 85f1eb6..0000000 --- a/graffiti/api/controllers/versions.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.api.controllers.v1.capability_type import \ - CapabilityTypeController -from graffiti.api.controllers.v1.namespace import NamespaceController -from graffiti.api.controllers.v1.resource import ResourceController - - -class V1Controller(object): - namespace = NamespaceController() - capability_type = CapabilityTypeController() - resource = ResourceController() diff --git a/graffiti/api/hooks.py b/graffiti/api/hooks.py deleted file mode 100644 index 2ded002..0000000 --- a/graffiti/api/hooks.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -# import json - -from pecan.hooks import PecanHook - - -class CorsHook(PecanHook): - def after(self, state): - state.response.headers['Access-Control-Allow-Origin'] = '*' - state.response.headers['Access-Control-Allow-Methods'] = \ - 'GET, PUT, POST, DELETE, OPTIONS' - state.response.headers['Access-Control-Allow-Headers'] = \ - 'origin, authorization, accept, content-type, X-Auth-Token' - - if not state.response.headers['Content-Length']: - state.response.headers['Content-Length'] = \ - str(len(state.response.body)) - - # TODO(lakshmi): this fails in Python 3.3, don't know why -# if state.response.headers['Content-Type'].find('json') != -1: - # Sort the Response Body's JSON -# json_str = json.loads(state.response.body) -# state.response.body = json.dumps(json_str, sort_keys=True) diff --git a/graffiti/api/model/__init__.py b/graffiti/api/model/__init__.py deleted file mode 100644 index 5b68b9e..0000000 --- a/graffiti/api/model/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -def init_model(): - pass diff --git a/graffiti/api/model/v1/__init__.py b/graffiti/api/model/v1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/api/model/v1/capability.py b/graffiti/api/model/v1/capability.py deleted file mode 100644 index 84ba796..0000000 --- a/graffiti/api/model/v1/capability.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import wsme -from wsme import types - - -class Capability(types.Base): - properties = wsme.wsattr({types.text: types.text}, mandatory=True) - capability_type = wsme.wsattr(types.text, mandatory=True) - capability_type_namespace = wsme.wsattr(types.text, mandatory=True) - - _wsme_attr_order = ('properties', 'capability_type', - 'capability_type_namespace') - - def __init__(self, **kwargs): - super(Capability, self).__init__(**kwargs) diff --git a/graffiti/api/model/v1/capability_type.py b/graffiti/api/model/v1/capability_type.py deleted file mode 100644 index 1250449..0000000 --- a/graffiti/api/model/v1/capability_type.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import wsme -from wsme import types - -from graffiti.api.model.v1.derived_type import DerivedType -from graffiti.api.model.v1.property_type import PropertyType -from graffiti.common.db_utils import DbTransformer - - -class CapabilityType(types.Base, DbTransformer): - - name = wsme.wsattr(types.text, mandatory=True) - namespace = wsme.wsattr(types.text, mandatory=True) - description = wsme.wsattr(types.text, mandatory=False) - properties = wsme.wsattr({types.text: PropertyType}, mandatory=False) - derived_from = wsme.wsattr(DerivedType, mandatory=False) - - def __init__(self, **kwargs): - super(CapabilityType, self).__init__(**kwargs) diff --git a/graffiti/api/model/v1/capability_type_derived_prop.py b/graffiti/api/model/v1/capability_type_derived_prop.py deleted file mode 100644 index 972b649..0000000 --- a/graffiti/api/model/v1/capability_type_derived_prop.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import wsme -from wsme import types - -from graffiti.api.model.v1.derived_property_type import DerivedPropertyType -from graffiti.api.model.v1.derived_type import DerivedType -from graffiti.api.model.v1.property_type import PropertyType -from graffiti.common.db_utils import DbTransformer - - -class CapabilityTypeDerivedProperties(types.Base, DbTransformer): - - name = wsme.wsattr(types.text, mandatory=True) - namespace = wsme.wsattr(types.text, mandatory=True) - description = wsme.wsattr(types.text, mandatory=False) - properties = wsme.wsattr({types.text: PropertyType}, mandatory=False) - derived_properties = wsme.wsattr({types.text: DerivedPropertyType}, - mandatory=False) - derived_from = wsme.wsattr(DerivedType, mandatory=False) - - def __init__(self, **kwargs): - super(CapabilityTypeDerivedProperties, self).__init__(**kwargs) diff --git a/graffiti/api/model/v1/capability_type_key.py b/graffiti/api/model/v1/capability_type_key.py deleted file mode 100644 index 3eb1d02..0000000 --- a/graffiti/api/model/v1/capability_type_key.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import wsme -from wsme import types - - -class CapabilityTypeKey(types.Base): - name = wsme.wsattr(types.text, mandatory=True) - namespace = wsme.wsattr(types.text, mandatory=True) - - _wsme_attr_order = ('name', 'namespace') - - def __init__(self, **kwargs): - super(CapabilityTypeKey, self).__init__(**kwargs) - - def __hash__(self): - return hash((self.name, self.namespace)) - - def __eq__(self, other): - return (self.name, self.namespace) == (other.name, other.namespace) diff --git a/graffiti/api/model/v1/dao/__init__.py b/graffiti/api/model/v1/dao/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/api/model/v1/dao/captype_dao.py b/graffiti/api/model/v1/dao/captype_dao.py deleted file mode 100644 index 5dc7c17..0000000 --- a/graffiti/api/model/v1/dao/captype_dao.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -class CapabilityTypeDAOBase(object): - - def __init__(self, **kwargs): - super(CapabilityTypeDAOBase, self).__init__(**kwargs) - self._type = "CapabilityTypeDAOBase" - - def get_type(self): - return self._type - - def get_capability_type(self, name, namespace): - return None - - def get_capability_type_with_derived_properties(self, name, namespace): - return None - - def find_capability_types(self, query_string): - return [] - - def set_capability_type(self, capability_type=None): - pass - - def put_capability_type(self, name, namespace, capability_type=None): - pass - - def delete_capability_type(self, name, namespace): - pass diff --git a/graffiti/api/model/v1/dao/captype_dao_factory.py b/graffiti/api/model/v1/dao/captype_dao_factory.py deleted file mode 100644 index 1680155..0000000 --- a/graffiti/api/model/v1/dao/captype_dao_factory.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.api.model.v1.dao.captype_db_dao \ - import DBCapabilityTypeDAO -from graffiti.api.model.v1.dao.captype_file_dao \ - import FileCapabilityTypeDAO -from graffiti.api.model.v1.dao.captype_mem_dao \ - import MemCapabilityTypeDAO - - -class CapabilityTypeDAOFactory(object): - - def __init__(self, **kwargs): - super(CapabilityTypeDAOFactory, self).__init__(**kwargs) - - @staticmethod - def create(dao_type, **kwargs): - if dao_type.lower() == 'memory': - print "Dictionary persistence = memory" - return MemCapabilityTypeDAO(**kwargs) - elif dao_type.lower() == "db": - print "Dictionary persistence = db" - return DBCapabilityTypeDAO(**kwargs) - elif dao_type.lower() == "file": - print "Dictionary persistence = File" - return FileCapabilityTypeDAO(**kwargs) - - return None diff --git a/graffiti/api/model/v1/dao/captype_db_dao.py b/graffiti/api/model/v1/dao/captype_db_dao.py deleted file mode 100644 index 4200d6c..0000000 --- a/graffiti/api/model/v1/dao/captype_db_dao.py +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.api.model.v1.capability_type import CapabilityType -from graffiti.api.model.v1.capability_type_derived_prop import \ - CapabilityTypeDerivedProperties -from graffiti.api.model.v1.dao.captype_dao import CapabilityTypeDAOBase -from graffiti.api.model.v1.derived_property_type import DerivedPropertyType -from graffiti.api.model.v1.derived_type import DerivedType -from graffiti.api.model.v1.property_type import PropertyType - -from graffiti.db import api as dbapi -import json -from wsme.rest.json import fromjson -from wsme.rest.json import tojson - - -class DBCapabilityTypeDAO(CapabilityTypeDAOBase): - - def __init__(self, **kwargs): - super(DBCapabilityTypeDAO, self).__init__(**kwargs) - self._type = "DBCapabilityTypeDAO" - - def get_type(self): - return self._type - - def _to_model(self, db_captype): - model_captype = CapabilityType.to_model(db_captype) - if db_captype.parent_name == 'null': - model_captype.derived_from = None - else: - model_captype.derived_from = DerivedType( - name=db_captype.parent_name, - namespace=db_captype.parent_namespace) - - property_types = {} - db_properties = json.loads(db_captype.properties_text) - for id in db_properties: - property_types[id] = fromjson(PropertyType, db_properties[id]) - model_captype.properties = property_types - - return model_captype - - def _to_model_derived(self, db_captype, derived_props): - model_captype = CapabilityTypeDerivedProperties.to_model(db_captype) - - if db_captype.parent_name == 'null': - model_captype.derived_from = None - else: - model_captype.derived_from = DerivedType( - name=db_captype.parent_name, - namespace=db_captype.parent_namespace) - - property_types = {} - db_properties = json.loads(db_captype.properties_text) - for id in db_properties: - property_types[id] = fromjson(PropertyType, db_properties[id]) - model_captype.properties = property_types - - if derived_props: - derived_property_types = {} - for key in derived_props: - props = derived_props[key] - db_properties = json.loads(props) - for id in db_properties: - derived_props_model = fromjson( - DerivedPropertyType, - db_properties[id]) - derived_props_model.derived_from_capability_namespace =\ - key.namespace - derived_props_model.derived_from_capability_name = key.name - derived_property_types[id] = derived_props_model - - model_captype.derived_properties = derived_property_types - - return model_captype - - def _to_dict(self, model_captype): - captype_dict = model_captype.to_dict() - - properties = model_captype.properties - db_property_types = {} - if properties: - for k, v in properties.items(): - json_data = tojson(PropertyType, v) - db_property_types[k] = json_data - captype_dict['properties_text'] = json.dumps(db_property_types) - - derived_from = model_captype.derived_from - if derived_from: - captype_dict["parent_name"] = model_captype.derived_from.name - captype_dict["parent_namespace"] =\ - model_captype.derived_from.namespace - - return captype_dict - - def get_capability_type(self, name, namespace): - db_capability_type = dbapi.capability_type_get(name, namespace) - if not db_capability_type: - return None - - return self._to_model(db_capability_type) - - def get_capability_type_with_derived_properties(self, name, namespace): - cap_type_prop_dict = dbapi.capability_type_get_with_derived_properties( - name, - namespace) - db_capability_type = cap_type_prop_dict['cap_type'] - - derived_props = None - if 'derived_properties' in cap_type_prop_dict.keys(): - derived_props = cap_type_prop_dict['derived_properties'] - - if not db_capability_type: - res = CapabilityType(CapabilityType(), status_code=404, - error="CapabilityType Not Found") - return res - - return self._to_model_derived(db_capability_type, derived_props) - - def find_capability_types(self, query_string): - # TODO(wko): add support for query_string - db_capability_types = dbapi.capability_type_get_all() - capability_types = [] - for db_ct in db_capability_types: - capability_types.append(self._to_model(db_ct)) - return capability_types - - def set_capability_type(self, capability_type=None): - created_capability_type = dbapi.capability_type_create( - self._to_dict(capability_type)) - return self._to_model(created_capability_type) - - def put_capability_type(self, name, namespace, capability_type=None): - # Update a Capability Type - if capability_type: - db_capability_type = dbapi.capability_type_update( - name, namespace, self._to_dict(capability_type)) - return self._to_model(db_capability_type) - - def delete_capability_type(self, name, namespace): - db_capability_type = dbapi.capability_type_get(name, namespace) - if db_capability_type: - dbapi.capability_type_delete(name, namespace) - return self._to_model(db_capability_type) diff --git a/graffiti/api/model/v1/dao/captype_file_dao.py b/graffiti/api/model/v1/dao/captype_file_dao.py deleted file mode 100644 index 66825eb..0000000 --- a/graffiti/api/model/v1/dao/captype_file_dao.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -from graffiti.api.model.v1.capability_type import CapabilityType -from graffiti.api.model.v1.dao.captype_dao import CapabilityTypeDAOBase -import json -from oslo.config import cfg -from wsme.rest.json import fromjson -from wsme.rest.json import tojson - - -class FileCapabilityTypeDAO(CapabilityTypeDAOBase): - - def __init__(self, **kwargs): - super(FileCapabilityTypeDAO, self).__init__(**kwargs) - self._graffiti_folder = cfg.CONF.FILE_PERSISTENCE.dictionary_folder - self._filename = "dictionary.json" - self._dictionaryfile = self._graffiti_folder + self._filename - self._capability_types = self.__file_to_memory() - self._type = "FileCapabilityTypeDAO" - - def get_type(self): - return self._type - - def get_capability_type(self, name, namespace): - id = namespace + ":" + name - return self._capability_types[id] - - def find_capability_types(self, query_string): - return self._capability_types.itervalues() - - def set_capability_type(self, capability_type): - id = capability_type.namespace + ":" + capability_type.name - self._capability_types[id] = capability_type - self.__memory_to_file() - return capability_type - - def put_capability_type(self, name, namespace, capability_type): - id = namespace + ":" + name - self._capability_types[id] = capability_type - self.__memory_to_file() - return capability_type - - def delete_capability_type(self, name, namespace): - id = namespace + ":" + name - capability_type = None - if self._capability_types[id]: - capability_type = self._capability_types[id] - self._capability_types.pop(id) - self.__memory_to_file() - return capability_type - - def __file_to_memory(self): - try: - capability_types = {} - with open(self._dictionaryfile, "r") as gfile: - doc = json.load(gfile) - for id in doc: - capability_types[id] = fromjson(CapabilityType, doc[id]) - return capability_types - - except IOError: - with open(self._dictionaryfile, "w+") as gfile: - gfile.write("") - return {} - - def __memory_to_file(self): - file_capability_types = {} - for (id, capability_type) in self._capability_types.items(): - json_data = tojson(CapabilityType, capability_type) - file_capability_types[id] = json_data - - with open(self._dictionaryfile, "w+") as gfile: - json.dump(file_capability_types, gfile) diff --git a/graffiti/api/model/v1/dao/captype_mem_dao.py b/graffiti/api/model/v1/dao/captype_mem_dao.py deleted file mode 100644 index fcd5fd1..0000000 --- a/graffiti/api/model/v1/dao/captype_mem_dao.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.api.model.v1.dao.captype_dao import CapabilityTypeDAOBase - - -class MemCapabilityTypeDAO(CapabilityTypeDAOBase): - - def __init__(self, **kwargs): - super(MemCapabilityTypeDAO, self).__init__(**kwargs) - self._capability_types = {} - self._type = "MemCapabilityTypeDAO" - - def get_type(self): - return self._type - - def get_capability_type(self, name, namespace): - id = namespace + ":" + name - return self._capability_types[id] - - def find_capability_types(self, query_string): - return self._capability_types.itervalues() - - def set_capability_type(self, capability_type): - id = capability_type.namespace + ":" + capability_type.name - self._capability_types[id] = capability_type - - return capability_type - - def put_capability_type(self, name, namespace, capability_type): - id = namespace + ":" + name - self._capability_types[id] = capability_type - - return capability_type - - def delete_capability_type(self, name, namespace): - id = namespace + ":" + name - capability_type = None - if self._capability_types[id]: - capability_type = self._capability_types[id] - self._capability_types.pop(id) - - return capability_type diff --git a/graffiti/api/model/v1/dao/ns_dao.py b/graffiti/api/model/v1/dao/ns_dao.py deleted file mode 100755 index 6345b21..0000000 --- a/graffiti/api/model/v1/dao/ns_dao.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -class NSDAOBase(object): - - def __init__(self, **kwargs): - super(NSDAOBase, self).__init__(**kwargs) - self._type = "NSDAOBase" - - def get_type(self): - return self._type - - def get_namespace(self, namespace_name): - return None - - def find_namespaces(self, query_string): - return [] - - def set_namespace(self, namespace): - pass - - def put_namespace(self, namespace_name, namespace): - pass - - def delete_namespace(self, namespace_name): - pass diff --git a/graffiti/api/model/v1/dao/ns_dao_factory.py b/graffiti/api/model/v1/dao/ns_dao_factory.py deleted file mode 100755 index abad8b3..0000000 --- a/graffiti/api/model/v1/dao/ns_dao_factory.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -from graffiti.api.model.v1.dao.ns_db_dao \ - import DBNSDAO -from graffiti.api.model.v1.dao.ns_file_dao \ - import FileNSDAO -from graffiti.api.model.v1.dao.ns_mem_dao \ - import MemNSDAO -from oslo.config import cfg - - -class NSDAOFactory(object): - - __dao = None - __dao_type = cfg.CONF.DEFAULT.persistence_type - - def __init__(self, **kwargs): - super(NSDAOFactory, self).__init__(**kwargs) - - @staticmethod - def create(dao_type, **kwargs): - if dao_type.lower() == 'memory': - print "Namespace persistence = memory" - NSDAOFactory.__dao = MemNSDAO(**kwargs) - return NSDAOFactory.__dao - elif dao_type.lower() == "db": - print "Namespace persistence = db" - NSDAOFactory.__dao = DBNSDAO(**kwargs) - return NSDAOFactory.__dao - elif dao_type.lower() == "file": - print "Namespace persistence = File" - NSDAOFactory.__dao = FileNSDAO(**kwargs) - return NSDAOFactory.__dao - - return None - - @staticmethod - def get(): - if NSDAOFactory.__dao: - return NSDAOFactory.__dao - else: - return NSDAOFactory.create( - NSDAOFactory.__dao_type) diff --git a/graffiti/api/model/v1/dao/ns_db_dao.py b/graffiti/api/model/v1/dao/ns_db_dao.py deleted file mode 100755 index 265a3ab..0000000 --- a/graffiti/api/model/v1/dao/ns_db_dao.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.api.model.v1.dao.ns_dao import NSDAOBase -from graffiti.api.model.v1.namespace import Namespace -from graffiti.db import api as dbapi - - -class DBNSDAO(NSDAOBase): - - def __init__(self, **kwargs): - super(DBNSDAO, self).__init__(**kwargs) - self._type = "DBNSDAO" - - def get_type(self): - return self._type - - def get_namespace(self, namespace_name): - db_namespace = dbapi.namespace_get(namespace_name) - if not db_namespace: - res = Namespace(Namespace(), status_code=404, - error="Namespace Not Found") - return res - - return Namespace.to_model(db_namespace) - - def find_namespaces(self, query_string): - dbnamespaces = dbapi.namespace_get_all() - namespaces = [] - for ns in dbnamespaces: - namespaces.append(Namespace.to_model(ns)) - return namespaces - - def set_namespace(self, namespace): - created_namespace = dbapi.namespace_create(namespace.to_dict()) - return Namespace.to_model(created_namespace) - - def put_namespace(self, namespace_name, namespace): - dbapi.namespace_update(namespace_name, namespace.to_dict()) - - def delete_namespace(self, namespace_name): - db_namespace = dbapi.namespace_get(namespace_name) - if db_namespace: - dbapi.namespace_delete(namespace_name) - return Namespace.to_model(db_namespace) diff --git a/graffiti/api/model/v1/dao/ns_file_dao.py b/graffiti/api/model/v1/dao/ns_file_dao.py deleted file mode 100755 index def060d..0000000 --- a/graffiti/api/model/v1/dao/ns_file_dao.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -from graffiti.api.model.v1.dao.ns_dao import NSDAOBase -from graffiti.api.model.v1.namespace import Namespace - -import json - -from oslo.config import cfg - -from wsme.rest.json import fromjson -from wsme.rest.json import tojson - - -class FileNSDAO(NSDAOBase): - - def __init__(self, **kwargs): - super(FileNSDAO, self).__init__(**kwargs) - self._graffiti_folder = cfg.CONF.FILE_PERSISTENCE.dictionary_folder - self._filename = "namespaces.json" - self._namespacefile = self._graffiti_folder + self._filename - self._namespaces = self.__file_to_memory() - self._type = "FileNSDAO" - - def get_type(self): - return self._type - - def get_namespace(self, namespace_name): - return self._namespaces[namespace_name] - - def find_namespaces(self, query_string): - return self._namespaces.itervalues() - - def set_namespace(self, namespace): - self._namespaces[namespace.name] = namespace - self.__memory_to_file() - return namespace - - def put_namespace(self, namespace_name, namespace): - self._namespaces[namespace_name] = namespace - self.__memory_to_file() - return namespace - - def delete_namespace(self, namespace_name): - namespace = None - if self._namespaces[namespace_name]: - namespace = self._namespaces[namespace_name] - self._namespaces.pop(namespace_name) - self.__memory_to_file() - return namespace - - def __file_to_memory(self): - try: - namespaces = {} - with open(self._namespacefile, "r") as gfile: - doc = json.load(gfile) - for namespace in doc: - namespaces[namespace] = fromjson(Namespace, doc[namespace]) - return namespaces - - except IOError: - with open(self._namespacefile, "w+") as gfile: - gfile.write("") - return {} - - def __memory_to_file(self): - namespaces = {} - for (namespace_name, namespace) in self._namespaces.items(): - json_data = tojson(Namespace, namespace) - namespaces[namespace_name] = json_data - - with open(self._namespacefile, "w+") as gfile: - json.dump(namespaces, gfile) diff --git a/graffiti/api/model/v1/dao/ns_mem_dao.py b/graffiti/api/model/v1/dao/ns_mem_dao.py deleted file mode 100755 index 7ffe296..0000000 --- a/graffiti/api/model/v1/dao/ns_mem_dao.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.api.model.v1.dao.ns_dao import NSDAOBase - - -class MemNSDAO(NSDAOBase): - - def __init__(self, **kwargs): - super(MemNSDAO, self).__init__(**kwargs) - self._namespaces = {} - self._type = "MemNSDAO" - - def get_type(self): - return self._type - - def get_namespace(self, namespace_name): - return self._namespaces[namespace_name] - - def find_namespaces(self, query_string): - return self._namespaces.itervalues() - - def set_namespace(self, namespace): - self._namespaces[namespace.name] = namespace - return namespace - - def put_namespace(self, namespace_name, namespace): - self._namespaces[namespace.name] = namespace - return namespace - - def delete_namespace(self, namespace_name): - namespace = None - if self._namespaces[namespace_name]: - namespace = self._namespaces[namespace_name] - self._namespaces.pop(namespace_name) - - return namespace diff --git a/graffiti/api/model/v1/dao/resource_dao.py b/graffiti/api/model/v1/dao/resource_dao.py deleted file mode 100644 index a3d8dfc..0000000 --- a/graffiti/api/model/v1/dao/resource_dao.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -class ResourceDAOBase(object): - - def __init__(self, **kwargs): - super(ResourceDAOBase, self).__init__(**kwargs) - self._type = "ResourceDAOBase" - - def get_type(self): - return self._type - - def get_resource(self, id): - return None - - def find_resources(self, query_string): - return [] - - def set_resource(self, id, resource): - pass - - def delete_resource(self, id): - pass diff --git a/graffiti/api/model/v1/dao/resource_dao_factory.py b/graffiti/api/model/v1/dao/resource_dao_factory.py deleted file mode 100644 index 1e6b934..0000000 --- a/graffiti/api/model/v1/dao/resource_dao_factory.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.api.model.v1.dao.resource_db_dao import DBResourceDAO -from graffiti.api.model.v1.dao.resource_file_dao import FileResourceDAO -from graffiti.api.model.v1.dao.resource_mem_dao import MemResourceDAO - - -class ResourceDAOFactory(object): - - def __init__(self, **kwargs): - super(ResourceDAOFactory, self).__init__(**kwargs) - - @staticmethod - def create(dao_type, **kwargs): - if dao_type.lower() == 'memory': - print "Directory persistence = memory" - return MemResourceDAO(**kwargs) - elif dao_type.lower() == 'file': - print "Directory persistence = file" - return FileResourceDAO(**kwargs) - elif dao_type.lower() == 'db': - print "Directory persistence = db" - return DBResourceDAO(**kwargs) - - return None diff --git a/graffiti/api/model/v1/dao/resource_db_dao.py b/graffiti/api/model/v1/dao/resource_db_dao.py deleted file mode 100644 index 2fd6faf..0000000 --- a/graffiti/api/model/v1/dao/resource_db_dao.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -from graffiti.api.model.v1.dao.resource_dao import ResourceDAOBase - - -#TODO(Lakshmi): Implement db persistence for resource -class DBResourceDAO(ResourceDAOBase): - - def __init__(self, **kwargs): - super(DBResourceDAO, self).__init__(**kwargs) - self._type = "DBResourceDAO" - - def get_type(self): - return self._type - - def get_resource(self, id): - pass - - def find_resources(self, resource_query): - pass - - def set_resource(self, id=None, resource_definition=None): - pass - - def delete_resource(self, id): - pass diff --git a/graffiti/api/model/v1/dao/resource_file_dao.py b/graffiti/api/model/v1/dao/resource_file_dao.py deleted file mode 100644 index d5534fe..0000000 --- a/graffiti/api/model/v1/dao/resource_file_dao.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -from graffiti.api.model.v1.dao.resource_dao import ResourceDAOBase - - -class FileResourceDAO(ResourceDAOBase): - - def __init__(self, **kwargs): - super(FileResourceDAO, self).__init__(**kwargs) - self._type = "FileResourceDAO" - - def get_type(self): - return self._type - - def get_resource(self, id): - pass - - def find_resources(self, query_string): - pass - - def set_resource(self, id=None, resource_definition=None): - pass - - def delete_resource(self, id): - pass - - def _generate_id(self): - pass diff --git a/graffiti/api/model/v1/dao/resource_mem_dao.py b/graffiti/api/model/v1/dao/resource_mem_dao.py deleted file mode 100644 index 6267847..0000000 --- a/graffiti/api/model/v1/dao/resource_mem_dao.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -from graffiti.api.model.v1.dao.resource_dao import ResourceDAOBase - - -class MemResourceDAO(ResourceDAOBase): - - def __init__(self, **kwargs): - super(MemResourceDAO, self).__init__(**kwargs) - self._resources = dict() - self._last_id = 0 - self._type = "MemResourceDAO" - - def get_type(self): - return self._type - - def get_resource(self, id): - return self._resources[id] - - def find_resources(self, query_string): - return self._resources - - def set_resource(self, id=None, resource=None): - if not id: - id = self._generate_id() - - self._resources[id] = resource - return id - - def delete_resource(self, id): - pass - - def _generate_id(self): - return_value = self._last_id - self._last_id += 1 - - return return_value diff --git a/graffiti/api/model/v1/derived_property_type.py b/graffiti/api/model/v1/derived_property_type.py deleted file mode 100644 index 9acc071..0000000 --- a/graffiti/api/model/v1/derived_property_type.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.api.model.v1.property_type import PropertyType -import wsme -from wsme import types - - -class DerivedPropertyType(PropertyType): - '''mandatory is set to False instead of True, since wsme will complain - while deserializing the properties to model. derived properties are - dynamically added after the model is deserialized from persistence - ''' - derived_from_capability_namespace = wsme.wsattr( - types.text, mandatory=False) - derived_from_capability_name = wsme.wsattr(types.text, mandatory=False) - - _wsme_attr_order = ('type', 'description', 'default', 'required', - 'minimum', 'maximum', 'minLength', 'maxLength', - 'pattern', 'confidential', 'items', 'uniqueItems', - 'additionalItems', 'derived_from_capability_name', - 'derived_from_capability_namespace') - - def __init__(self, **kwargs): - super(DerivedPropertyType, self).__init__(**kwargs) diff --git a/graffiti/api/model/v1/derived_type.py b/graffiti/api/model/v1/derived_type.py deleted file mode 100644 index 31442b6..0000000 --- a/graffiti/api/model/v1/derived_type.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import wsme -from wsme import types - - -class DerivedType(types.Base): - name = wsme.wsattr(types.text, mandatory=True) - namespace = wsme.wsattr(types.text, mandatory=True) - - _wsme_attr_order = ('name', 'namespace') - - def __init__(self, **kwargs): - super(DerivedType, self).__init__(**kwargs) diff --git a/graffiti/api/model/v1/namespace.py b/graffiti/api/model/v1/namespace.py deleted file mode 100644 index 43a86c1..0000000 --- a/graffiti/api/model/v1/namespace.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -import wsme -from wsme import types - -from graffiti.common.db_utils import DbTransformer - - -class Namespace(types.Base, DbTransformer): - name = wsme.wsattr(types.text, mandatory=True) - scope = wsme.wsattr(types.text, mandatory=True) - owner = wsme.wsattr(types.text, mandatory=False) - - def __init__(self, **kwargs): - super(Namespace, self).__init__(**kwargs) diff --git a/graffiti/api/model/v1/property.py b/graffiti/api/model/v1/property.py deleted file mode 100644 index 19126b8..0000000 --- a/graffiti/api/model/v1/property.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import wsme -from wsme import types - - -class Property(types.Base): - name = wsme.wsattr(types.text, mandatory=True) - value = wsme.wsattr(types.text, mandatory=True) - - _wsme_attr_order = ('name', 'value') - - def __init__(self, **kwargs): - super(Property, self).__init__(**kwargs) diff --git a/graffiti/api/model/v1/property_item_type.py b/graffiti/api/model/v1/property_item_type.py deleted file mode 100755 index 228147a..0000000 --- a/graffiti/api/model/v1/property_item_type.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import wsme -from wsme import types - - -class ItemType(types.Base): - type = wsme.wsattr(types.text, mandatory=True) - enum = wsme.wsattr([types.text], mandatory=False) - - _wsme_attr_order = ('type', 'enum') - - def __init__(self, **kwargs): - super(ItemType, self).__init__(**kwargs) diff --git a/graffiti/api/model/v1/property_type.py b/graffiti/api/model/v1/property_type.py deleted file mode 100644 index fc84af7..0000000 --- a/graffiti/api/model/v1/property_type.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.api.model.v1.property_item_type import ItemType -import wsme -from wsme import types - - -class PropertyType(types.Base): - type = wsme.wsattr(types.text, mandatory=True) - description = wsme.wsattr(types.text, mandatory=False) - default = wsme.wsattr(types.text, mandatory=False) - required = wsme.wsattr(bool, mandatory=False, default=False) - - # fields for type = string - minimum = wsme.wsattr(int, mandatory=False) - maximum = wsme.wsattr(int, mandatory=False) - - # fields for type = integer, number - minLength = wsme.wsattr(int, mandatory=False) - maxLength = wsme.wsattr(int, mandatory=False) - pattern = wsme.wsattr(types.text, mandatory=False) - confidential = wsme.wsattr(bool, mandatory=False) - - # fields for type = array - items = wsme.wsattr(ItemType, mandatory=False) - uniqueItems = wsme.wsattr(bool, mandatory=False) - minItems = wsme.wsattr(int, mandatory=False) - maxItems = wsme.wsattr(int, mandatory=False) - additionalItems = wsme.wsattr(bool, mandatory=False) - - _wsme_attr_order = ('type', 'description', 'default', 'required', - 'minimum', 'maximum', 'minLength', 'maxLength', - 'pattern', 'confidential', 'items', 'uniqueItems', - 'additionalItems') - - def __init__(self, **kwargs): - super(PropertyType, self).__init__(**kwargs) diff --git a/graffiti/api/model/v1/provider.py b/graffiti/api/model/v1/provider.py deleted file mode 100644 index 77f8457..0000000 --- a/graffiti/api/model/v1/provider.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import wsme -from wsme import types - - -class Provider(types.Base): - id = wsme.wsattr(types.text, mandatory=True) - - _wsme_attr_order = ('id',) - - def __init__(self, **kwargs): - super(Provider, self).__init__(**kwargs) diff --git a/graffiti/api/model/v1/requirement.py b/graffiti/api/model/v1/requirement.py deleted file mode 100644 index c140648..0000000 --- a/graffiti/api/model/v1/requirement.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import wsme -from wsme import types - - -class Requirement(types.Base): - criterion = wsme.wsattr(types.text, mandatory=True) - capability_type = wsme.wsattr(types.text, mandatory=True) - capability_type_namespace = wsme.wsattr(types.text, mandatory=True) - - _wsme_attr_order = ('criterion', 'capability_type', - 'capability_type_namespace') - - def __init__(self, **kwargs): - super(Requirement, self).__init__(**kwargs) diff --git a/graffiti/api/model/v1/resource.py b/graffiti/api/model/v1/resource.py deleted file mode 100644 index 76c2aed..0000000 --- a/graffiti/api/model/v1/resource.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import wsme -from wsme import types - -from graffiti.api.model.v1.capability import Capability -from graffiti.api.model.v1.provider import Provider -from graffiti.api.model.v1.requirement import Requirement - - -class Resource(types.Base): - id = wsme.wsattr(types.text, mandatory=True) - type = wsme.wsattr(types.text, mandatory=True) - name = wsme.wsattr(types.text, mandatory=True) - description = wsme.wsattr(types.text, mandatory=False) - provider = wsme.wsattr(Provider, mandatory=True) - properties = wsme.wsattr({types.text: types.text}, mandatory=False) - capabilities = wsme.wsattr([Capability], mandatory=True) - requirements = wsme.wsattr([Requirement], mandatory=True) - - _wsme_attr_order = ('id', 'name', 'description', 'type', - 'provider', 'properties', 'capabilities', - 'requirements') - - def __init__(self, **kwargs): - super(Resource, self).__init__(**kwargs) diff --git a/graffiti/api/model/v1/resource_query.py b/graffiti/api/model/v1/resource_query.py deleted file mode 100644 index 2a1b756..0000000 --- a/graffiti/api/model/v1/resource_query.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import wsme -from wsme import types - - -class ResourceQuery(types.Base): - resource_types = wsme.wsattr([types.text], mandatory=False) - - #_wsme_attr_order = ('resource_types') - - def __init__(self, **kwargs): - super(ResourceQuery, self).__init__(**kwargs) diff --git a/graffiti/api/service.py b/graffiti/api/service.py deleted file mode 100644 index fb5010f..0000000 --- a/graffiti/api/service.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import sys - -from oslo.config import cfg - - -def prepare_service(argv=None): - if argv is None: - argv = sys.argv - - # when running unit tests, argv is inaccessible for some unknown - # reason; need to revisit this logic again running under Apache2 - # TODO(lakshmi): figure this out - try: - cfg.CONF(argv[3:], project='graffiti') - except BaseException: - pass diff --git a/graffiti/api/tests/__init__.py b/graffiti/api/tests/__init__.py deleted file mode 100644 index 7a15b4a..0000000 --- a/graffiti/api/tests/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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/graffiti/api/tests/base.py b/graffiti/api/tests/base.py deleted file mode 100644 index 5a957c0..0000000 --- a/graffiti/api/tests/base.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2010-2011 OpenStack Foundation -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# 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. - -import os - -import fixtures -from oslo.config import cfg -import testtools - -_TRUE_VALUES = ('True', 'true', '1', 'yes') - -# DEFAULT group -default_controller_group = cfg.OptGroup('DEFAULT') -default_controller_opts = [ - cfg.StrOpt( - 'persistence_type', - default="memory", - help=("persistence options. " - "values = 'memory' or 'file' or 'db")) -] - -cfg.CONF.register_group(default_controller_group) -cfg.CONF.register_opts(default_controller_opts, - group=default_controller_group) - -# FILE_PERSISTENCE group -file_controller_group = cfg.OptGroup('FILE_PERSISTENCE') -file_controller_opts = [ - cfg.StrOpt( - 'dictionary_folder', - default="/tmp/graffiti-dictionary-test/", - help=("Absolute path of the file for persisting dictionary") - ) -] - -cfg.CONF.register_group(file_controller_group) -cfg.CONF.register_opts(file_controller_opts, - group=file_controller_group) - - -class TestCase(testtools.TestCase): - - """Test case base class for all unit tests.""" - - def setUp(self): - """Run before each test method to initialize test environment.""" - - super(TestCase, self).setUp() - test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0) - try: - test_timeout = int(test_timeout) - except ValueError: - # If timeout value is invalid do not set a timeout. - test_timeout = 0 - if test_timeout > 0: - self.useFixture(fixtures.Timeout(test_timeout, gentle=True)) - - self.useFixture(fixtures.NestedTempfile()) - self.useFixture(fixtures.TempHomeDir()) - - if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES: - stdout = self.useFixture(fixtures.StringStream('stdout')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) - if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES: - stderr = self.useFixture(fixtures.StringStream('stderr')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) - - self.log_fixture = self.useFixture(fixtures.FakeLogger()) diff --git a/graffiti/api/tests/pecan_base.py b/graffiti/api/tests/pecan_base.py deleted file mode 100644 index 4068f3d..0000000 --- a/graffiti/api/tests/pecan_base.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -""" -pecan_base ------------------------------------ - -Tests through the pecan framework. -""" -import os - -import pecan -import pecan.testing - -#from oslo.config import cfg - -from graffiti.api.tests import base -from graffiti.common import driver_factory - - -class TestCase(base.TestCase): - PATH_PREFIX = '/v1' - - def setUp(self): - super(TestCase, self).setUp() - self.app = self._make_app() - #cfg.CONF.set_override(name='type', override='Local', - # group='resource_controller') - driver_factory.DriverFactory() - - def _make_app(self): - root_dir = self.path_get() - self.config = { - 'app': { - 'root': 'graffiti.api.controllers.root.RootController', - 'modules': ['graffiti.api'], - 'template_path': '%s/graffiti/templates' % root_dir, - }, - } - - return pecan.testing.load_test_app(self.config) - - def tearDown(self): - super(TestCase, self).tearDown() - pecan.set_config({}, overwrite=True) - - def path_get(self, project_file=None): - root = os.path.abspath(os.path.join(os.path.dirname(__file__), - '..', - '..', )) - if project_file: - return os.path.join(root, project_file) - else: - return root - - def delete(self, path, expect_errors=False, headers=None, - extra_environ=None, status=None): - full_path = self.PATH_PREFIX + path - response = self.app.delete( - str(full_path), headers=headers, status=status, - extra_environ=extra_environ, expect_errors=expect_errors) - - return response - - def get_json(self, path, expect_errors=False, headers=None, - extra_environ=None, q=[], **params): - full_path = self.PATH_PREFIX + path - query_params = {'q.field': [], - 'q.value': [], - 'q.op': [], } - for query in q: - for name in ['field', 'op', 'value']: - query_params['q.%s' % name].append(query.get(name, '')) - - all_params = {} - all_params.update(params) - if q: - all_params.update(query_params) - - response = self.app.get(full_path, - params=all_params, - headers=headers, - extra_environ=extra_environ, - expect_errors=expect_errors) - - if not expect_errors: - response = response - - return response - - def post_json(self, path, params, expect_errors=False, headers=None, - method="post", extra_environ=None, status=None): - full_path = self.PATH_PREFIX + path - - response = getattr(self.app, "%s_json" % method)( - str(full_path), params=params, headers=headers, - status=status, extra_environ=extra_environ, - expect_errors=expect_errors) - - return response - - def put_json(self, path, params, expect_errors=False, headers=None, - extra_environ=None, status=None): - return self.post_json(path=path, params=params, - expect_errors=expect_errors, headers=headers, - extra_environ=extra_environ, status=status, - method="put") diff --git a/graffiti/api/tests/samples/captypes_os-glance-2014-1.json b/graffiti/api/tests/samples/captypes_os-glance-2014-1.json deleted file mode 100644 index ecc4178..0000000 --- a/graffiti/api/tests/samples/captypes_os-glance-2014-1.json +++ /dev/null @@ -1,555 +0,0 @@ -{ "capability_type_list" : -[ - { - "name": "ArchLinux", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "arch", - "required": false, - "confidential": false - } - } - }, - { - "name": "CENTOS", - "namespace": "OS:GLANCE:2014-1", - "description": "Community Enterprise Operating System", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "centos", - "required": false, - "confidential": false - } - } - }, - { - "name": "Debian", - "namespace": "OS:GLANCE:2014-1", - "description": "Debian", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "debian", - "required": false, - "confidential": false - } - } - }, - { - "name": "Fedora", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "fedora", - "required": false, - "confidential": false - } - } - }, - { - "name": "FreeBSD", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "freebsd", - "required": false, - "confidential": false - } - } - }, - { - "name": "GentooLinux", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "gentoo", - "required": false, - "confidential": false - } - } - }, - { - "name": "MS-DOS", - "namespace": "OS:GLANCE:2014-1", - "description": "Microsoft Disc Operating System", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "msdos", - "required": false, - "confidential": false - } - } - }, - { - "name": "MandrakeLinux", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "mandrake", - "required": false, - "confidential": false - } - } - }, - { - "name": "MandrivaEnterpriseServer", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "mes", - "required": false, - "confidential": false - } - } - }, - { - "name": "MandrivaLinux", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "mandriva", - "required": false, - "confidential": false - } - } - }, - { - "name": "MicrosoftWindows", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "windows", - "required": false, - "confidential": false - } - } - }, - { - "name": "NetBSD", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "netbsd", - "required": false, - "confidential": false - } - } - }, - { - "name": "NovellNetWare", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "netware", - "required": false, - "confidential": false - } - } - }, - { - "name": "OpenBSD", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "openbsd", - "required": false, - "confidential": false - } - } - }, - { - "name": "OpenSUSE", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "opensuse", - "required": false, - "confidential": false - } - } - }, - { - "name": "OpenSolaris", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "opensolaris", - "required": false, - "confidential": false - } - } - }, - { - "name": "RedHatEnterpriseLinux", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "rhel", - "required": false, - "confidential": false - } - } - }, - { - "name": "SUSELinuxEnterpriseDesktop", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "sled", - "required": false, - "confidential": false - } - } - }, - { - "name": "Ubuntu", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "os_distro": { - "type": "string", - "description": "", - "defaultValue": "ubuntu", - "required": false, - "confidential": false - } - } - }, - { - "name": "ComputeDriver", - "namespace": "OS:GLANCE:2014-1", - "description": "These are properties specific to compute drivers. For a list of all hypervisors, see here: https://wiki.openstack.org/wiki/HypervisorSupportMatrix", - "properties": {} - }, - { - "name": "VMwareComputeDriver", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "ComputeDriver", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "vmware_adaptertype": { - "type": "choice", - "description": "Indicates the virtual SCSI or IDE controller used by the hypervisor.", - "required": false, - "confidential": false, - "itemType": "string", - "items": [ - "lsiLogic", - " busLogic", - "ide" - ] - }, - "vmware_ostype": { - "type": "string", - "description": "A VMware GuestID which describes the operating system installed in the image. This will be passed to the hypervisor when creating a virtual machine. See thinkvirt.com for a list of valid values. If this is not specified, it will default to otherGuest.", - "required": false, - "confidential": false - }, - "vmware_image_version": { - "type": "string", - "description": "Currently unused, set it to 1.", - "defaultValue": "1", - "required": false, - "confidential": false - } - } - }, - { - "name": "XenComputeDriver", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "ComputeDriver", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "auto_disk_config": { - "type": "boolean", - "description": "A boolean option. If true, the root partition on the disk will be automatically resized before the instance boots. This value is only taken into account by the Compute service when using a Xen-based hypervisor with the XenAPI driver. The Compute service will only attempt to resize if there is a single partition on the image, and only if the partition is in ext3 or ext4 format.", - "required": false, - "confidential": false - }, - "os_type": { - "type": "choice", - "description": "The operating system installed on the image. For example, linux or windows. The XenAPI driver contains logic that will take different actions depending on the value of the os_type parameter of the image. For example, for images where os_type=windows, it creates a FAT32-based swap partition instead of a Linux swap partition, and it limits the injected host name to less than 16 characters.", - "required": false, - "confidential": false, - "itemType": "string", - "items": [ - "linux", - "windows" - ] - } - } - }, - { - "name": "libvirtDriver", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "derived_from": { - "name": "ComputeDriver", - "namespace": "OS:GLANCE:2014-1" - }, - "properties": { - "hw_video_model": { - "type": "choice", - "description": "The video image driver used.", - "required": false, - "confidential": false, - "itemType": "string", - "items": [ - "vga", - "cirrus", - "vmvga", - "xen", - "gxl" - ] - } - } - }, - { - "name": "Image", - "namespace": "OS:GLANCE:2014-1", - "description": "A collection of files for a specific operating system (OS) that you use to create or rebuild a server. OpenStack provides pre-built images. You can also create custom images, or snapshots, from servers that you have launched. Custom images can be used for data backups or as \"gold\" images for additional servers.", - "properties": { - "instance_uuid": { - "type": "string", - "description": "For snapshot images, this is the UUID of the server used to create this image.", - "required": false, - "confidential": false, - "pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$" - }, - "kernel_id": { - "type": "string", - "description": "The ID of image stored in Glance that should be used as the kernel when booting an AMI-style image.", - "required": false, - "confidential": false, - "pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$" - }, - "ramdisk_id": { - "type": "string", - "description": "The ID of image stored in Glance that should be used as the ramdisk when booting an AMI-style image.", - "required": false, - "confidential": false - } - } - }, - { - "name": "ImagePropertiesFilter", - "namespace": "OS:GLANCE:2014-1", - "description": "The ImagePropertiesFilter filters compute nodes that satisfy any architecture, hypervisor type, or virtual machine mode properties specified on the instance's image properties. Image properties are contained in the image dictionary in the request_spec.", - "properties": { - "hypervisor_type": { - "type": "choice", - "description": "The hypervisor type.", - "required": false, - "confidential": false, - "itemType": "string", - "items": [ - "xem", - "qemu", - "kvm", - "lxc", - "uml", - "vmware", - "hyperv" - ] - }, - "vm_mode": { - "type": "choice", - "description": "The virtual machine mode. This represents the host/guest ABI (application binary interface) used for the virtual machine.", - "required": false, - "confidential": false, - "itemType": "string", - "items": [ - "hvm", - "xen", - "uml", - "exe" - ] - }, - "architecture": { - "type": "choice", - "description": "The CPU architecture that must be supported by the hypervisor. For example, x86_64, arm, or ppc64. Run uname -m to get the architecture of a machine. We strongly recommend using the architecture data vocabulary defined by the libosinfo project for this purpose.", - "required": false, - "confidential": false, - "itemType": "string", - "items": [ - "alpha", - "armv71", - "cris", - "i686", - "ia64", - "lm32", - "m68k", - "microblaze", - "microblazeel", - "mips", - "mipsel", - "mips64", - "mips64el", - "openrisc", - "parisc", - "parisc64", - "ppc", - "ppc64", - "ppcemb", - "s390", - "s390x", - "sh4", - "sh4eb", - "sparc", - "sparc64", - "unicore32", - "x86_64", - "xtensa", - "xtensaeb" - ] - } - } - }, - { - "name": "OperatingSystem", - "namespace": "OS:GLANCE:2014-1", - "description": "", - "properties": { - "os_version": { - "type": "string", - "description": "", - "required": false, - "confidential": false - } - } - } -] -} \ No newline at end of file diff --git a/graffiti/api/tests/samples/resource_2014-1.json b/graffiti/api/tests/samples/resource_2014-1.json deleted file mode 100644 index 1fe72b9..0000000 --- a/graffiti/api/tests/samples/resource_2014-1.json +++ /dev/null @@ -1,47 +0,0 @@ -{"resource_list": [ - { - "name": "StandardResource", - "id": "0000-0000-0000-0000", - "description": "This is a standard resource definition", - "provider": { - "id": "1111-0000-0000-0000" - }, - "capabilities": [ - { - "capability_type": "StandardCapability1", - "capability_type_namespace": "TEST:RESOURCE:2014-1", - "properties": - { - "StandardCapabilityProperty1": "SCP1", - "StandardCapabilityProperty2": "SCP2" - } - }, - { - "capability_type": "StandardCapability2", - "capability_type_namespace": "TEST:RESOURCE:2014-1", - "properties": - { - "StandardCapabilityProperty3": "SCP3", - "StandardCapabilityProperty4": "SCP4" - } - }], - "properties": - { - "StandardResourceProperty1": "SRP1", - "StandardResourceProperty2": "SRP2" - }, - "requirements": [ - { - "capability_type": "StandardRequirement1", - "capability_type_namespace": "TEST:RESOURCE:2014-1", - "criterion": "StandardCriterion1" - }, - { - "capability_type": "StandardRequirement2", - "capability_type_namespace": "TEST:RESOURCE:2014-1", - "criterion": "StandardCriterion2" - }], - "type": "GFT::Local" - }] -} - diff --git a/graffiti/api/tests/test_controller_v1.py b/graffiti/api/tests/test_controller_v1.py deleted file mode 100644 index a980c0d..0000000 --- a/graffiti/api/tests/test_controller_v1.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -""" -test_controller_v1 ----------------------------------- - -Tests for `graffiti` module. -""" - -from graffiti.api.tests import base - -from graffiti.api.controllers.root import RootController -from graffiti.api.controllers.versions import V1Controller - -from graffiti.api.model.v1.dao.captype_dao_factory \ - import CapabilityTypeDAOFactory -from graffiti.api.model.v1.dao.ns_dao_factory \ - import NSDAOFactory -from graffiti.api.model.v1.dao.resource_dao_factory \ - import ResourceDAOFactory - - -class TestControllerV1(base.TestCase): - - def test_v1_exists(self): - root = RootController() - self.assertIn(hasattr(root, 'v1'), [True]) - - def test_v1_namespace_exists(self): - v1 = V1Controller() - self.assertIn(hasattr(v1, 'namespace'), [True]) - - def test_v1_namespace_controller_factory__memory(self): - rc = NSDAOFactory.create('memory') - self.assertEquals(rc.get_type(), 'MemNSDAO') - - # TODO(Lakshmi): Create folder before any tests run - # def test_v1_namespace_controller_factory__file(self): - # rc = NSControllerFactory.create('file') - # self.assertEquals(rc.get_type(), 'FileNSDAO') - - def test_v1_namespace_controller_factory__db(self): - rc = NSDAOFactory.create('db') - self.assertEquals(rc.get_type(), 'DBNSDAO') - - def test_v1_capability_type_exists(self): - v1 = V1Controller() - self.assertIn(hasattr(v1, 'capability_type'), [True]) - - def test_v1_capability_type_dao_factory__memory(self): - rc = CapabilityTypeDAOFactory.create('memory') - self.assertEquals(rc.get_type(), 'MemCapabilityTypeDAO') - - # TODO(Lakshmi): Create folder before any tests run - # def test_v1_capability_type_dao_factory__file(self): - # rc = CapabilityTypeDAOFactory.create('file') - # self.assertEquals(rc.get_type(), 'FileCapabilityTypeDAO') - - def test_v1_capability_type_dao_factory__db(self): - rc = CapabilityTypeDAOFactory.create('db') - self.assertEquals(rc.get_type(), 'DBCapabilityTypeDAO') - - def test_v1_resource_exists(self): - v1 = V1Controller() - self.assertIn(hasattr(v1, 'resource'), [True]) - - def test_v1_resource_dao_factory__memory(self): - rc = ResourceDAOFactory.create('memory') - self.assertEquals(rc.get_type(), 'MemResourceDAO') - - def test_v1_resource_dao_factory__file(self): - rc = ResourceDAOFactory.create('file') - self.assertEquals(rc.get_type(), 'FileResourceDAO') - - def test_v1_resource_dao_factory__db(self): - rc = ResourceDAOFactory.create('db') - self.assertEquals(rc.get_type(), 'DBResourceDAO') - - def test_v1_resource_controller_factory__unknown(self): - rc = ResourceDAOFactory.create('invalid_controller') - self.assertTrue(rc is None) diff --git a/graffiti/api/tests/test_graffiti.py b/graffiti/api/tests/test_graffiti.py deleted file mode 100644 index c7d73db..0000000 --- a/graffiti/api/tests/test_graffiti.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -""" -test_graffiti ----------------------------------- - -Tests for `graffiti` module. -""" -import json - -from graffiti.api.tests import pecan_base - -TEST_DATA_FILE = "graffiti/api/tests/samples/resource_2014-1.json" - - -def get_resource_list(): - json_data_file = open(TEST_DATA_FILE) - json_data = json_data_file.read() - json_data_file.close() - resource_list_json = json.loads(json_data)['resource_list'] - return resource_list_json - - -class TestGraffiti(pecan_base.TestCase): - - def test_get_all_empty(self): - response = self.get_json('/resource') - self.assertEqual(response.status_int, 200) - self.assertEqual(response.content_type, 'application/json') - self.assertEqual(response.json, []) - - def test_post(self): - standard_resource_json = get_resource_list()[0] - response = self.post_json('/resource', params=standard_resource_json) - self.assertEqual(response.status_int, 200) - self.assertEqual(response.content_type, 'application/json') - self.assertEqual(response.json, standard_resource_json) - - def test_get_one(self): - standard_resource_json = get_resource_list()[0] - self.post_json('/resource', params=standard_resource_json) - response = self.get_json('/resource/%s' % standard_resource_json['id']) - self.assertEqual(response.status_int, 200) - self.assertEqual(response.content_type, 'application/json') - self.assertEqual(response.json, standard_resource_json) - - def test_put(self): - standard_resource_json = get_resource_list()[0] - self.post_json('/resource', params=standard_resource_json) - standard_resource_json['name'] = 'RENAMED' - response = self.put_json('/resource/%s' % standard_resource_json['id'], - params=standard_resource_json) - self.assertEqual(response.status_int, 200) - self.assertEqual(response.content_type, 'application/json') - self.assertEqual(response.json, standard_resource_json) diff --git a/graffiti/common/__init__.py b/graffiti/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/common/db_utils.py b/graffiti/common/db_utils.py deleted file mode 100644 index 6a34517..0000000 --- a/graffiti/common/db_utils.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -# look at heat/openstack/common/gettextutils.py when we actually need -# to implement this method - - -from wsme import types as wtypes - - -class DbTransformer(): - - @classmethod - def to_model(model, db_entity): - # Transform a db_entity to model object - db_items = db_entity.as_dict().items() - items = dict((key, value) for key, value in db_items) - return model(**items) - - def to_dict(self): - # Return the wsme_attributes names:values as a dict - names = [] - for attribute in self._wsme_attributes: - names.append(attribute.name) - - values = {} - for name in names: - value = getattr(self, name) - if value == wtypes.Unset: - value = None - values.update({name: value}) - return values diff --git a/graffiti/common/driver_factory.py b/graffiti/common/driver_factory.py deleted file mode 100644 index 59bb5c6..0000000 --- a/graffiti/common/driver_factory.py +++ /dev/null @@ -1,149 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -from graffiti.common import exception - -from oslo.config import cfg - -from stevedore import dispatch - -driver_opts = [ - cfg.ListOpt('enabled_drivers', - default=['local', 'glance', 'nova', 'cinder'], - help='List of drivers to enable. Missing drivers, or ' - 'drivers which can not be loaded will be ' - 'treated as a fatal exception.'), -] - -CONF = cfg.CONF -CONF.register_opts(driver_opts) - - -def get_driver(resource_type): - """Simple method to get a ref to an instance of a driver by the - supported resource type. - - Driver loading is handled by the DriverFactory class. This method - conveniently wraps that class and returns the actual driver object. - - :param resource_type: the resource type supported by a driver - :returns: An instance of a class which implements - graffiti.drivers.base.BaseResourceDriver - :raises: DriverNotFound if the requested driver_name could not be - found in the "graffiti.drivers" namespace. - - """ - - try: - factory = DriverFactory() - print "resource types", factory.resource_types - print "resource type", resource_type - if resource_type in factory.resource_types.keys(): - driver_name = factory.resource_types[resource_type] - return factory[driver_name].obj - else: - raise exception.DriverNotFoundForResourceType( - resource_type=resource_type - ) - - except KeyError: - raise exception.DriverNotFound(driver_name=driver_name) - - -def get_driver_by_name(driver_name): - """Simple method to get a ref to an instance of a driver by the - name. - - Driver loading is handled by the DriverFactory class. This method - conveniently wraps that class and returns the actual driver object. - - :param driver_name: name of the registered driver - :returns: An instance of a class which implements - graffiti.drivers.base.BaseResourceDriver - :raises: DriverNotFound if the requested driver_name could not be - found in the "graffiti.drivers" namespace. - - """ - - try: - factory = DriverFactory() - return factory[driver_name].obj - except KeyError: - raise exception.DriverNotFound(driver_name=driver_name) - - -def get_resource_types(): - """Returns a dictionary of resource type and driver name - :returns:dictionary with resource type as key and driver name - as its value - """ - return DriverFactory()._resource_types - - -class DriverFactory(object): - """Discover, load and manage the drivers available.""" - - _driver_manager = None - _resource_types = {} - - def __init__(self): - if not DriverFactory._driver_manager: - DriverFactory._init_driver_manager() - print "Loaded drivers:", self.names - - def __getitem__(self, name): - return self._driver_manager[name] - - @classmethod - def _init_driver_manager(self): - if self._driver_manager: - return - - def _catch_driver_not_found(mgr, ep, exc): - if (isinstance(exc, exception.DriverLoadError) and - ep.name not in CONF.enabled_drivers): - return - raise exc - - def _check_func(ext): - return ext.name in CONF.enabled_drivers - - self._driver_manager = dispatch.NameDispatchExtensionManager( - 'graffiti.drivers', - _check_func, - invoke_on_load=True, - on_load_failure_callback=_catch_driver_not_found - ) - - #Get supported resource types - for driver_name in self._driver_manager.names(): - driver = self._driver_manager[driver_name].obj - driver_resource_types = driver.get_resource_types() - for type in driver_resource_types: - self._resource_types[type] = driver_name - - @property - def names(self): - """The list of driver names available.""" - return self._driver_manager.names() - - @property - def resource_types(self): - """Returns all resource types supported by all the drivers - :returns dictionary with resource type as key and driver name - as its value - """ - return self._resource_types diff --git a/graffiti/common/exception.py b/graffiti/common/exception.py deleted file mode 100644 index 9bad58e..0000000 --- a/graffiti/common/exception.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -import sys - -from graffiti.openstack.common.gettextutils import _ -from graffiti.openstack.common.log import logging - -_FATAL_EXCEPTION_FORMAT_ERRORS = False - -logger = logging.getLogger(__name__) - - -class GraffitiException(Exception): - """Base Graffiti Exception - - To correctly use this class, inherit from it and define - a 'msg_fmt' property. That msg_fmt will get printf'd - with the keyword arguments provided to the constructor. - - """ - message = _("An unknown exception occurred.") - - def __str__(self): - return self.message - - def __init__(self, **kwargs): - self.kwargs = kwargs - - try: - self.message = self.msg_fmt % kwargs - except KeyError: - exc_info = sys.exc_info() - #kwargs doesn't match a variable in the message - #log the issue and the kwargs - logger.exception(_('Exception in string format operation')) - for name, value in kwargs.iteritems(): - logger.error("%s: %s" % (name, value)) - - if _FATAL_EXCEPTION_FORMAT_ERRORS: - raise exc_info[0], exc_info[1], exc_info[2] - - #def __str__(self): - # return unicode(self.message).encode('UTF-8') - - def __unicode__(self): - return unicode(self.message) - - def __deepcopy__(self, memo): - return self.__class__(**self.kwargs) - - -class NotFound(GraffitiException): - msg_fmt = _("Object not found") - - -class DuplicateEntry(GraffitiException): - msg_fmt = _("Database object already exists") - - -class DriverNotFound(NotFound): - msg_fmt = _("Failed to load driver %(driver_name)s.") - - -class DriverLoadError(GraffitiException): - msg_fmt = _("Driver %(driver)s could not be loaded. Reason: %(reason)s.") - - -class MethodNotSupported(GraffitiException): - msg_fmt = _("Method %(method)s is not supported by this driver") - - -class DriverNotFoundForResourceType(NotFound): - msg_fmt = _("Cannot find a registered driver for the resource " - "type %(resource_type)s") diff --git a/graffiti/common/utilities/__init__.py b/graffiti/common/utilities/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/common/utilities/capability_type_tree.py b/graffiti/common/utilities/capability_type_tree.py deleted file mode 100644 index a69a537..0000000 --- a/graffiti/common/utilities/capability_type_tree.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -from graffiti.api.model.v1.capability_type_key import CapabilityTypeKey -from graffiti.common.utilities.capability_type_tree_node \ - import CapabilityTypeTreeNode - - -class CapabilityTypeTree(): - - def __init__(self, **kwargs): - self.root_types = {} - self.types_with_external_root = {} - - def build(self, capability_type_list): - capability_types = {} - for cap_type in capability_type_list: - # todo(wko): raise error if duplicate found - key = CapabilityTypeKey(name=cap_type.name, - namespace=cap_type.namespace) - capability_types[key] = cap_type - - # Handle: 1) No parent 2) No children (no-op) - # 3) Parent in tree - # 4) Parent not processed, yet - # 5) More than one root in input (not common ancestor) - # 6) Type has parent, but not in input (external parent) - types_with_unmapped_parents = {} - for current_key, current_cap_type in capability_types.iteritems(): - current_node = CapabilityTypeTreeNode() - current_node.cap_type = current_cap_type - - # Scenario 1 & 5 - if not current_cap_type.derived_from \ - or not current_cap_type.derived_from.name: - self.root_types[current_key] = current_node - continue - - if self.insert_node(self.root_types, current_key, current_node): - # Scenario 3 - continue - elif self.insert_node(types_with_unmapped_parents, - current_key, current_node): - # Scenario 3 (not converged) - continue - else: - # Scenario 4 part a - types_with_unmapped_parents[current_key] = current_node - - # Scenario 4 part b - # Perform eventual convergence on roots - self.converge_unmapped_types(self.root_types, - types_with_unmapped_parents) - - # Perform eventual convergence on types_with_unmapped_parents - self.converge_unmapped_types(types_with_unmapped_parents, - types_with_unmapped_parents) - - # Scenario 6 - self.types_with_external_root.update(types_with_unmapped_parents) - - def insert_node(self, cap_types, current_key, current_node): - # For each cap_type - # if it is the parent of the current_node.cap_type - # set root_node as the current_node.parent_node - # add the current_node to root_node.children - # break - # else - # recursively check if parent is in root_node.children - # break if found - result = False - if cap_types: - i = 0 - for root_key, root_node in cap_types.iteritems(): - # todo(wko): derived_from should be a CapabilityTypeKey - current_parent_name = current_node.cap_type.derived_from.name - current_parent_namesp = \ - current_node.cap_type.derived_from.namespace - - if root_key.name == current_parent_name and\ - root_key.namespace == current_parent_namesp: - current_node.parent_node = root_node - root_node.children[current_key] = current_node - result = True - break - - result = self.insert_node(root_node.children, current_key, - current_node) - if result: - break - i += 1 - - return result - - def converge_unmapped_types(self, root_types, types_with_unmapped_parents): - - previous_loop_unmapped_parents = 0 - num_loops_without_change = 0 - - while len(types_with_unmapped_parents) > 0 \ - and num_loops_without_change < 2: - types_with_found_parent = [] - for unmapped_key, unmapped_node in \ - types_with_unmapped_parents.iteritems(): - result = self.insert_node(root_types, unmapped_key, - unmapped_node) - if result: - types_with_found_parent.append(unmapped_key) - continue - - for mapped_parent in types_with_found_parent: - del types_with_unmapped_parents[mapped_parent] - - this_loop_unmapped_parents = len(types_with_unmapped_parents) - if previous_loop_unmapped_parents == this_loop_unmapped_parents: - num_loops_without_change += 1 - else: - num_loops_without_change = 0 - - previous_loop_unmapped_parents = this_loop_unmapped_parents diff --git a/graffiti/common/utilities/capability_type_tree_node.py b/graffiti/common/utilities/capability_type_tree_node.py deleted file mode 100644 index 1f403e5..0000000 --- a/graffiti/common/utilities/capability_type_tree_node.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -class CapabilityTypeTreeNode(): - - def __init__(self, **kwargs): - self.children = {} - self.parent_node = None - self.cap_type = None diff --git a/graffiti/common/utils.py b/graffiti/common/utils.py deleted file mode 100644 index 33a0ece..0000000 --- a/graffiti/common/utils.py +++ /dev/null @@ -1,202 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -# look at heat/openstack/common/gettextutils.py when we actually need -# to implement this method - -import glob -import httplib2 -import json -import os - -from graffiti.api.model.v1.capability import Capability -from graffiti.api.model.v1.derived_type import DerivedType - - -DICTIONARY_DATA_FOLDER = "etc/dictionary" -NAMESPACE_STRING = "Namespace*" -CAPABILITY_TYPE_STRING = "CapabilityType*" - -__namespace_resource_type_dict = dict() -__namespace_property_format_dict = dict() -__namespace_list = [] - -__namespace_dict = dict() -__property_dict = dict() - -TAG_IDENTIFIER = "_TAG" - - -# TODO(travis): need localization strategy -def _(msg): - return msg - - -def load_dictionary(**kwargs): - cur_dir = os.getcwd() - os.chdir(DICTIONARY_DATA_FOLDER) - - for namespace_file in glob.glob(NAMESPACE_STRING): - print "Loading Namespace file: %s" % namespace_file - load_namespace(namespace_file) - - if kwargs.get('url'): - for namespace in __namespace_list: - print "Loading Capability types for namespace: %s" % \ - namespace['namespace'] - load_capability_type_http(kwargs.get('url'), - namespace['namespace']) - else: - for cap_type_file in glob.glob(CAPABILITY_TYPE_STRING): - print "Loading Capability type file: %s" % cap_type_file - load_capability_type(cap_type_file) - - os.chdir(cur_dir) - - -def load_namespace(namespacefile): - with open(namespacefile) as json_file: - json_data = json.load(json_file) - #print(json_data) - - for namespace in json_data: - __namespace_resource_type_dict[namespace['namespace']] = \ - namespace['resource_types'] - __namespace_property_format_dict[namespace['namespace']] = \ - namespace['property_format'] - __namespace_list.append(namespace) - - -def load_capability_type(cap_type_file): - with open(cap_type_file) as json_file: - json_data = json.load(json_file) - capability_type_list = json_data['capability_type_list'] - load_capability_type_list(capability_type_list) - - -def load_capability_type_http(url, namespace, **kwargs): - token = "" - with open("../temp-token.txt") as tokenfile: - token = tokenfile.readline() - kwargs.setdefault('headers', {})['X-Auth-Token'] = token - http_client = httplib2.Http() - resp, body = http_client.request(url + namespace, - 'GET', **kwargs) - json_data = json.loads(body) - load_capability_type_list(json_data) - - -def load_capability_type_list(capability_type_list): - for cap_type in capability_type_list: - derived_type = DerivedType() - derived_type.name = cap_type['name'] - derived_type.namespace = cap_type['namespace'] - - key_names = [] - for key in cap_type['properties'].keys(): - property_name = key - if cap_type['properties'][key]['type'] == "choice": - #Property name and item in each choice as key - for item in cap_type['properties'][key]['items']: - dict_key = property_name + item - key_names.append(dict_key) - else: - if 'defaultValue' in cap_type['properties'][key].keys(): - #Property name and default value as key - dict_key = property_name + \ - str(cap_type['properties'][key] - ['defaultValue']) - key_names.append(dict_key) - else: - #Just use the property name as key - dict_key = property_name - key_names.append(dict_key) - - property_dict = dict() - if derived_type.namespace in __namespace_dict.keys(): - property_dict = __namespace_dict[derived_type.namespace] - - for key in key_names: - property_dict[key.lower()] = derived_type - - #Add capability itself as property - behaves as a TAG - tag_name = cap_type['name'] + TAG_IDENTIFIER - property_dict[tag_name.lower()] = derived_type - - __namespace_dict[derived_type.namespace] = property_dict - - -def get_namespace_resource_type_dict(): - return __namespace_resource_type_dict - - -def get_namespace_property_format_dict(): - return __namespace_property_format_dict - - -def get_qualifier(property_name, property_value): - if property_value: - key1 = property_name.lower() + property_value.lower() - key2 = property_name.lower() - else: - key1 = property_name.lower() - - #First loop. Make sure key1 is not found anywhere - for namespace in __namespace_dict.keys(): - property_dict = __namespace_dict[namespace] - if key1 in property_dict.keys(): - return property_dict[key1] - - if property_value: - #Second loop. If not found first, use key2 - for namespace in __namespace_dict.keys(): - property_dict = __namespace_dict[namespace] - if key2 in property_dict.keys(): - return property_dict[key2] - - return None - - -def resolve_capability(key, value, target_resource, - default_namespace=None, - default_name=None): - resolved_type = None - resolved_namespace = None - - cap_and_namespace = get_qualifier( - key, - value - ) - if cap_and_namespace: - resolved_type = cap_and_namespace.name - resolved_namespace = cap_and_namespace.namespace - else: - resolved_namespace = target_resource.type + "::Default" - resolved_type = "AdditionalProperties" - - resolved_capability = None - for capability in target_resource.capabilities: - if capability.capability_type_namespace == resolved_namespace \ - and capability.capability_type == resolved_type: - resolved_capability = capability - - if not resolved_capability: - resolved_capability = Capability() - resolved_capability.capability_type_namespace = resolved_namespace - resolved_capability.capability_type = resolved_type - resolved_capability.properties = {} - target_resource.capabilities.append(resolved_capability) - - resolved_capability.properties[key] = value diff --git a/graffiti/db/__init__.py b/graffiti/db/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/db/api.py b/graffiti/db/api.py deleted file mode 100644 index 09d9910..0000000 --- a/graffiti/db/api.py +++ /dev/null @@ -1,263 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -# WKO: testing branch dependency -# Lakshmi : testing branch dependency on db -# import copy -from oslo.config import cfg - -from graffiti.api.model.v1.derived_type import DerivedType -from graffiti.common import exception as exc -from graffiti.db import models -from graffiti.openstack.common.db import exception as db_exc -from graffiti.openstack.common.db.sqlalchemy import session as db_session - -CONF = cfg.CONF -CONF.import_group("database", "graffiti.openstack.common.db.options") -_FACADE = None - -BASE = models.Base - - -def setup_db(): - try: - engine = get_engine() - BASE.metadata.create_all(engine) - except Exception: - return False - return True - - -def drop_db(): - try: - BASE.metadata.drop_all(get_engine()) - except Exception: - return False - return True - - -def _get_facade_instance(): - """Generate an instance of the DB Facade. - """ - global _FACADE - if _FACADE is None: - if CONF.database.connection is None: - print("Warning: [database] connection not configured.") - _FACADE = db_session.EngineFacade( - CONF.database.connection, - **dict(CONF.database.iteritems())) - return _FACADE - - -def _destroy_facade_instance(): - """Destroys the db facade instance currently in use. - """ - global _FACADE - _FACADE = None - - -def get_engine(): - """Returns the global instance of our database engine. - """ - facade = _get_facade_instance() - return facade.get_engine() - - -def get_session(autocommit=True, expire_on_commit=False): - """Returns a database session from our facade. - """ - facade = _get_facade_instance() - return facade.get_session(autocommit=autocommit, - expire_on_commit=expire_on_commit) - - -def cleanup(): - """Manually clean up our database engine. - """ - _destroy_facade_instance() - - -def model_query(model, session=None): - """Query helper. - - :param model: base model to query - """ - session = session or get_session() - query = session.query(model) - return query - - -def __entity_get_by_name(kls, entity_name, session): - query = model_query(kls, session) - return query.filter_by(name=entity_name).first() - - -def __entity_get_by_name_namespace(kls, entity_name, entity_namespace, - session): - query = model_query(kls, session) - return query.filter_by(name=entity_name, - namespace=entity_namespace).first() - - -def _entity_get_all(kls, **kwargs): - kwargs = dict((k, v) for k, v in kwargs.iteritems() if v) - - query = model_query(kls) - entities = query.filter_by(**kwargs).all() - - return entities - - -def named_entity_update(kls, entity_name, values): - session = get_session() - - with session.begin(): - entity = __entity_get_by_name(kls, entity_name, session) - if entity is None: - raise exc.NotFound("%s %s not found" % (kls.__name__, entity_name)) - - entity.update(values.copy()) - session.add(entity) - - return entity - - -def named_namespace_entity_update(kls, entity_name, entity_namespace, values): - session = get_session() - - with session.begin(): - entity = __entity_get_by_name_namespace(kls, entity_name, - entity_namespace, session) - if entity is None: - raise exc.NotFound( - "%s %s %s not found" % (kls.__name__, entity_namespace, - entity_name)) - - entity.update(values.copy()) - session.add(entity) - - return entity - - -# BEGIN Namespace -def namespace_get(name): - query = model_query(models.Namespace, get_session()) - return query.filter_by(name=name).first() - - -def namespace_get_all(): - return _entity_get_all(models.Namespace) - - -def namespace_create(values): - namespace = models.Namespace() - namespace.update(values.copy()) - - session = get_session() - with session.begin(): - try: - namespace.save(session=session) - except db_exc.DBDuplicateEntry as e: - raise exc.DuplicateEntry("Duplicate entry for Namespace: %s" - % e.columns) - - return namespace - - -def namespace_update(name, values): - return named_entity_update(models.Namespace, name, values) - - -def namespace_delete(name): - namespace = namespace_get(name) - - if namespace: - session = get_session() - with session.begin(): - session.delete(namespace) - - -# BEGIN CapabilityType -def capability_type_get(name, namespace): - query = model_query(models.CapabilityType, get_session()) - return query.filter_by(name=name, namespace=namespace).first() - - -def capability_type_get_with_derived_properties(name, namespace): - cap_type_prop_dict = dict() - db_capability_type = capability_type_get(name, namespace) - if db_capability_type.parent_name and db_capability_type.parent_namespace: - property_dict = dict() - property_dict = __get_derived_properties( - db_capability_type.parent_name, - db_capability_type.parent_namespace, - property_dict - ) - cap_type_prop_dict['derived_properties'] = property_dict - - cap_type_prop_dict['cap_type'] = db_capability_type - return cap_type_prop_dict - - -def __get_derived_properties(name, namespace, property_dict): - db_capability_type = capability_type_get(name, namespace) - properties_text = db_capability_type.properties_text - if properties_text: - derived_type = DerivedType() - derived_type.name = name - derived_type.namespace = namespace - property_dict[derived_type] = properties_text - - if db_capability_type.parent_name and db_capability_type.parent_namespace: - __get_derived_properties( - db_capability_type.parent_name, - db_capability_type.parent_namespace, - property_dict - ) - - return property_dict - - -def capability_type_get_all(): - return _entity_get_all(models.CapabilityType) - - -def capability_type_create(values): - capability_type = models.CapabilityType() - capability_type.update(values.copy()) - - session = get_session() - with session.begin(): - try: - capability_type.save(session=session) - except db_exc.DBDuplicateEntry as e: - raise exc.DuplicateEntry("Duplicate entry for CapabilityType: %s" - % e.columns) - - return capability_type - - -def capability_type_update(name, namespace, values): - return named_namespace_entity_update(models.CapabilityType, - name, namespace, values) - - -def capability_type_delete(name, namespace): - capability_type = capability_type_get(name, namespace) - - if capability_type: - session = get_session() - with session.begin(): - session.delete(capability_type) diff --git a/graffiti/db/migration/README b/graffiti/db/migration/README deleted file mode 100644 index 683f9be..0000000 --- a/graffiti/db/migration/README +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2012 New Dream Network, LLC (DreamHost) -# -# 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. - -The migrations in the alembic_migrations/versions contain the changes needed -to migrate from older graffiti releases to newer versions. A migration occurs -by executing a script that details the changes needed to upgrade/downgrade -the database. The migration scripts are ordered so that multiple scripts -can run sequentially to update the database. The scripts are executed by -graffiti's migration wrapper which uses the Alembic library to manage the -migration. - - -You can upgrade to the latest database version via: -$ graffiti-db-manage --config-file /path/to/graffiti.conf upgrade head - -To check the current database version: -$ graffiti-db-manage --config-file /path/to/graffiti.conf current - -To create a script to run the migration offline: -$ graffiti-db-manage --config-file /path/to/graffiti.conf upgrade head --sql - -To run the offline migration between specific migration versions: -$ graffiti-db-manage --config-file /path/to/graffiti.conf \ - upgrade : --sql - -Upgrade the database incrementally: -$ graffiti-db-manage --config-file /path/to/graffiti.conf \ - upgrade --delta <# of revs> - -Downgrade the database by a certain number of revisions: -$ graffiti-db-manage --config-file /path/to/graffiti.conf \ - downgrade --delta <# of revs> - -This utility should be also used to load Project Groups and Projects form a .yaml -file description. The description sample is provided in etc/projects.yaml. -$ graffiti-db-manage --config-file /path/to/graffiti.conf \ - load_projects /path/to/projects.yaml - - -DEVELOPERS: -A database migration script is required when you submit a change to graffiti -that alters the database model definition. The migration script is a special -python file that includes code to update/downgrade the database to match the -changes in the model definition. Alembic will execute these scripts in order to -provide a linear migration path between revision. The graffiti-db-manage -command can be used to generate migration template for you to complete. The -operations in the template are those supported by the Alembic migration library. - -$ graffiti-db-manage --config-file /path/to/graffiti.conf \ - revision -m "description of revision" --autogenerate - -This generates a prepopulated template with the changes needed to match the -database state with the models. You should inspect the autogenerated template -to ensure that the proper models have been altered. - -In rare circumstances, you may want to start with an empty migration template -and manually author the changes necessary for an upgrade/downgrade. You can -create a blank file via: - -$ graffiti-db-manage --config-file /path/to/graffiti.conf \ - revision -m "description of revision" - -The migration timeline should remain linear so that there is a clear path when -upgrading/downgrading. To verify that the timeline does branch, you can run -this command: -$ graffiti-db-manage --config-file /path/to/graffiti.conf check_migration - -If the migration path does branch, you can find the branch point via: -$ graffiti-db-manage --config-file /path/to/graffiti.conf history diff --git a/graffiti/db/migration/__init__.py b/graffiti/db/migration/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/db/migration/alembic.ini b/graffiti/db/migration/alembic.ini deleted file mode 100644 index 6197de7..0000000 --- a/graffiti/db/migration/alembic.ini +++ /dev/null @@ -1,60 +0,0 @@ -# A generic, single database configuration. - -[alembic] -# path to migration_graffiti scripts -script_location = alembic_migrations - -# template used to generate migration_graffiti files -# file_template = %%(rev)s_%%(slug)s - -# max length of characters to apply to the -# "slug" field -#truncate_slug_length = 40 - -# set to 'true' to run the environment during -# the 'revision' command, regardless of autogenerate -# revision_environment = false - -# default to an empty string because the graffiti migration_graffiti cli will -# extract the correct value and set it programatically before alembic is fully -# invoked. -#sqlalchemy.url = driver://user:pass@localhost/dbname -sqlalchemy.url = mysql://graffiti:graffiti@127.0.0.1:3306/graffiti -#sqlalchemy.url = sqlite:///graffiti.db -#sqlalchemy.url = sqlite:// - - -# Logging configuration -[loggers] -keys = root,sqlalchemy,alembic - -[handlers] -keys = console - -[formatters] -keys = generic - -[logger_root] -level = WARN -handlers = console -qualname = - -[logger_sqlalchemy] -level = WARN -handlers = -qualname = sqlalchemy.engine - -[logger_alembic] -level = INFO -handlers = -qualname = alembic - -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic - -[formatter_generic] -format = %(levelname)-5.5s [%(name)s] %(message)s -datefmt = %H:%M:%S diff --git a/graffiti/db/migration/alembic_migrations/README b/graffiti/db/migration/alembic_migrations/README deleted file mode 100644 index 98e4f9c..0000000 --- a/graffiti/db/migration/alembic_migrations/README +++ /dev/null @@ -1 +0,0 @@ -Generic single-database configuration. \ No newline at end of file diff --git a/graffiti/db/migration/alembic_migrations/env.py b/graffiti/db/migration/alembic_migrations/env.py deleted file mode 100644 index 5443827..0000000 --- a/graffiti/db/migration/alembic_migrations/env.py +++ /dev/null @@ -1,86 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012 New Dream Network, LLC (DreamHost) -# -# 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. - -from alembic import context -from sqlalchemy import engine_from_config, pool -from logging.config import fileConfig - -# this is the Alembic Config object, which provides -# access to the values within the .ini file in use. -config = context.config - -# Interpret the config file for Python logging. -# This line sets up loggers basically. -fileConfig(config.config_file_name) - -# add your model's MetaData object here -# for 'autogenerate' support -# from myapp import mymodel -# target_metadata = mymodel.Base.metadata -target_metadata = None - -# other values from the config, defined by the needs of env.py, -# can be acquired: -# my_important_option = config.get_main_option("my_important_option") -# ... etc. - - -def run_migrations_offline(): - """Run migrations in 'offline' mode. - - This configures the context with just a URL - and not an Engine, though an Engine is acceptable - here as well. By skipping the Engine creation - we don't even need a DBAPI to be available. - - Calls to context.execute() here emit the given string to the - script output. - - """ - url = config.get_main_option("sqlalchemy.url") - context.configure(url=url) - - with context.begin_transaction(): - context.run_migrations() - - -def run_migrations_online(): - """Run migrations in 'online' mode. - - In this scenario we need to create an Engine - and associate a connection with the context. - - """ - engine = engine_from_config( - config.get_section(config.config_ini_section), - prefix='sqlalchemy.', - poolclass=pool.NullPool) - - connection = engine.connect() - context.configure( - connection=connection, - target_metadata=target_metadata) - - try: - with context.begin_transaction(): - context.run_migrations() - finally: - connection.close() - -if context.is_offline_mode(): - run_migrations_offline() -else: - run_migrations_online() diff --git a/graffiti/db/migration/alembic_migrations/script.py.mako b/graffiti/db/migration/alembic_migrations/script.py.mako deleted file mode 100644 index 9570201..0000000 --- a/graffiti/db/migration/alembic_migrations/script.py.mako +++ /dev/null @@ -1,22 +0,0 @@ -"""${message} - -Revision ID: ${up_revision} -Revises: ${down_revision} -Create Date: ${create_date} - -""" - -# revision identifiers, used by Alembic. -revision = ${repr(up_revision)} -down_revision = ${repr(down_revision)} - -from alembic import op -import sqlalchemy as sa -${imports if imports else ""} - -def upgrade(): - ${upgrades if upgrades else "pass"} - - -def downgrade(): - ${downgrades if downgrades else "pass"} diff --git a/graffiti/db/migration/alembic_migrations/versions/001_create_dictionary_tables.py b/graffiti/db/migration/alembic_migrations/versions/001_create_dictionary_tables.py deleted file mode 100644 index 656c0b6..0000000 --- a/graffiti/db/migration/alembic_migrations/versions/001_create_dictionary_tables.py +++ /dev/null @@ -1,59 +0,0 @@ -# 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. - -"""create dictionary tables - -Revision ID: 001 -Revises: None -Create Date: 2014-03-18 07:36:33.498311 - -""" - -# revision identifiers, used by Alembic. -revision = '001' -down_revision = None - - -from alembic import op -import sqlalchemy as sa - - -def upgrade(): - op.create_table( - 'namespaces', - sa.Column('name', sa.String(length=255), nullable=False), - sa.Column('scope', sa.String(length=255), nullable=False), - sa.Column('owner', sa.String(length=2000), nullable=False), - sa.PrimaryKeyConstraint('name') - ) - op.create_table( - 'capability_types', - sa.Column('name', sa.String(length=255), nullable=False), - sa.Column('namespace', sa.String(length=255), - sa.ForeignKey('namespaces.name', onupdate="CASCADE", - ondelete="CASCADE"), - nullable=False), - sa.Column('description', sa.String(length=2000), nullable=True), - sa.Column('parent_name', sa.String(length=255), nullable=True), - sa.Column('parent_namespace', sa.String(length=255), nullable=True), - sa.Column('properties_text', sa.UnicodeText(), nullable=True), - sa.PrimaryKeyConstraint('name', 'namespace'), - sa.ForeignKeyConstraint(['parent_name', 'parent_namespace'], - ['capability_types.name', - 'capability_types.namespace'], - onupdate="CASCADE", ondelete="CASCADE") - ) - - -def downgrade(): - op.drop_table('capability_types') - op.drop_table('namespaces') diff --git a/graffiti/db/models.py b/graffiti/db/models.py deleted file mode 100644 index c19b0b3..0000000 --- a/graffiti/db/models.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -# WKO: testing branch dependencies - -""" -SQLAlchemy Models for storing graffiti -""" - -from oslo.config import cfg -import six.moves.urllib.parse as urlparse -from sqlalchemy.ext import declarative -from sqlalchemy.orm import relationship -# from sqlalchemy import schema - -# from sqlalchemy import Boolean -from sqlalchemy import Column -# from sqlalchemy import DateTime -# from sqlalchemy import Enum -from sqlalchemy import ForeignKey -from sqlalchemy import String -from sqlalchemy import Unicode -from sqlalchemy import UnicodeText - -from graffiti.openstack.common.db.sqlalchemy import models - -CONF = cfg.CONF - - -def table_args(): - engine_name = urlparse.urlparse(cfg.CONF.database_connection).scheme - if engine_name == 'mysql': - return {'mysql_engine': cfg.CONF.mysql_engine, - 'mysql_charset': "utf8"} - return None - - -class DictionaryBase(models.ModelBase): - metadata = None - - @declarative.declared_attr - def __tablename__(cls): - # NOTE(jkoelker) use the pluralized name of the class as the table - return cls.__name__.lower() + 's' - - def as_dict(self): - d = {} - for c in self.__table__.columns: - d[c.name] = self[c.name] - return d - - -Base = declarative.declarative_base(cls=DictionaryBase) - - -class CapabilityType(Base): - __tablename__ = 'capability_types' - - name = Column(String(255), primary_key=True) - namespace = Column(String(255), ForeignKey('namespaces.name')) - description = Column(String(2000)) - parent_name = Column(String(255)) - parent_namespace = Column(String(255)) - properties_text = Column(UnicodeText()) - - -class Namespace(Base): - - name = Column(String(255), primary_key=True) - scope = Column(Unicode(255)) - owner = Column(String(2000)) - capability_types =\ - relationship("CapabilityType", - primaryjoin=name == CapabilityType.namespace, - cascade="all, delete") diff --git a/graffiti/drivers/__init__.py b/graffiti/drivers/__init__.py deleted file mode 100644 index 0f613e8..0000000 --- a/graffiti/drivers/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'lakshmi' diff --git a/graffiti/drivers/base.py b/graffiti/drivers/base.py deleted file mode 100644 index e194cb7..0000000 --- a/graffiti/drivers/base.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -""" -Abstract base class for graffiti resource drivers. -""" - -import abc -import six - - -@six.add_metaclass(abc.ABCMeta) -class BaseDriver(object): - """Base class for all drivers. - - Defines resource and definitions interface. - Any loadable driver must implement the interfaces it supports - - """ - - resource = None - - #TBD in future - #definitions = None - - @abc.abstractmethod - def __init__(self): - pass - - @abc.abstractmethod - def get_resource_types(self): - """Returns the resource types supported by the implementing driver - :returns [str] List of resource type strings - """ - - -@six.add_metaclass(abc.ABCMeta) -class ResourceInterface(object): - - @abc.abstractmethod - def get_resource(self, resource_type, resource_id, auth_token, - endpoint_id=None, **kwargs): - """Retrieve the resource detail - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - :returns resource detail - """ - - @abc.abstractmethod - def find_resources(self, resource_query, auth_token, - endpoint_id=None, **kwargs): - """Find resources matching the query - :param resource_query: query object - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - :returns list of resources - """ - - @abc.abstractmethod - def create_resource(self, resource_type, resource, auth_token, - endpoint_id=None, **kwargs): - """Create resource - :param resource_type: resource_type set for this call - :param resource: resource detail - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - - @abc.abstractmethod - def update_resource(self, resource_type, resource_id, resource, - auth_token, endpoint_id=None, **kwargs): - """Update resource - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param resource: resource detail - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - - @abc.abstractmethod - def delete_resource(self, resource_type, resource_id, auth_token, - endpoint_id=None, **kwargs): - """Delete resource - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ diff --git a/graffiti/drivers/cinder.py b/graffiti/drivers/cinder.py deleted file mode 100644 index 7ae303c..0000000 --- a/graffiti/drivers/cinder.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.drivers import base -from graffiti.drivers.modules import cinder - - -class CinderResourceDriver(base.BaseDriver): - """This driver implements cinder resource driver interface - """ - - def __init__(self): - self.resource = cinder.CinderResourceDriver() - self.resource_types = ['OS::Cinder::Volume', - 'OS::Cinder::VolumeSnapshot'] - - def get_resource_types(self): - """Returns the resource types supported by the implementing driver - :returns [str] List of resource type strings - """ - return self.resource_types diff --git a/graffiti/drivers/glance.py b/graffiti/drivers/glance.py deleted file mode 100644 index b042893..0000000 --- a/graffiti/drivers/glance.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.drivers import base -from graffiti.drivers.modules import glance - - -class GlanceResourceDriver(base.BaseDriver): - """This driver implements glance resource driver interface - """ - - def __init__(self): - self.resource = glance.GlanceResourceDriver() - self.resource_types = ["OS::Glance::Image", "OS::Glance::Snapshot"] - - def get_resource_types(self): - """Returns the resource types supported by the implementing driver - :returns [str] List of resource type strings - """ - return self.resource_types diff --git a/graffiti/drivers/local.py b/graffiti/drivers/local.py deleted file mode 100644 index 798cf03..0000000 --- a/graffiti/drivers/local.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.drivers import base -from graffiti.drivers.modules import local - - -class LocalResourceDriver(base.BaseDriver): - """This driver implements resource interface locally by graffiti - """ - - def __init__(self): - self.resource = local.LocalResourceDriver() - self.resource_types = ["GFT::Local"] - - def get_resource_types(self): - """Returns the resource types supported by the implementing - driver - :returns [str] List of resource type strings - """ - return self.resource_types diff --git a/graffiti/drivers/modules/__init__.py b/graffiti/drivers/modules/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/drivers/modules/cinder.py b/graffiti/drivers/modules/cinder.py deleted file mode 100644 index 307cdf6..0000000 --- a/graffiti/drivers/modules/cinder.py +++ /dev/null @@ -1,262 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from cinderclient import client -from graffiti.api.model.v1.resource import Resource -from graffiti.common import exception -from graffiti.common import utils -from graffiti.drivers import base -from graffiti.openstack.common import log as logging - -import keystoneclient.v2_0.client as ksclient - -from oslo.config import cfg - - -LOG = logging.getLogger(__name__) - - -class CinderResourceDriver(base.ResourceInterface): - - def __init__(self): - super(CinderResourceDriver, self).__init__() - self.volume_type = 'OS::Cinder::Volume' - self.snapshot_type = 'OS::Cinder::VolumeSnapshot' - self.separator = "." - self.service_type = 'volume' - self.endpoint_type = 'publicURL' - self.default_namespace_suffix = "::Default" - self.unknown_properties_type = "AdditionalProperties" - self.unmodifiable_properties = [u'instance_uuid', u'kernel_id', - u'ramdisk_id', u'disk_format', - u'image_name', u'image_id', - u'readonly', u'container_format', - u'checksum', u'size'] - - def get_resource(self, resource_type, resource_id, auth_token, - endpoint_id=None, **kwargs): - """Retrieve the resource detail - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - :returns resource detail - """ - - cinder_client = self.__get_cinder_client(endpoint_id, auth_token) - - cinder_resource = None - - if resource_type == self.volume_type: - cinder_resource = cinder_client.volumes.get(resource_id) - elif resource_type == self.snapshot_type: - cinder_resource = cinder_client.volume_snapshots.get(resource_id) - - if cinder_resource: - cinder_resource = self.transform_to_resource( - resource_type, cinder_resource) - - return cinder_resource - - def update_resource(self, resource_type, resource_id, resource, auth_token, - endpoint_id=None, **kwargs): - """Update resource - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param resource: resource detail - :type param: graffiti.api.model.v1.resource.Resource - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - - cinder_client = self.__get_cinder_client(endpoint_id, auth_token) - - cinder_properties = {} - for capability in resource.capabilities: - if not capability.properties: - #if capability doesnt have properties add as TAG - key = capability.capability_type - cinder_properties[key] = utils.TAG_IDENTIFIER - else: - for property_name, property_value \ - in capability.properties.items(): - key = property_name - if property_value: - cinder_properties[key] = str(property_value) - - cinder_resource = None - - if resource_type == self.volume_type: - cinder_resource = cinder_client.volumes.get(resource_id) - elif resource_type == self.snapshot_type: - cinder_resource = cinder_client.volume_snapshots.get(resource_id) - - properties_to_remove = \ - self._get_merged_properties(cinder_resource).keys() - #TODO(Travis) metadata_to_delete = [] - for property_to_keep in cinder_properties: - try: - properties_to_remove.remove(property_to_keep) - except ValueError: - #Sometimes properties to delete don't exist on server - pass - - try: - cinder_resource.set_metadata(cinder_resource, cinder_properties) - #TODO(Travis) cinder_client.volumes. - # delete_metadata(volume, properties_to_remove) - except AttributeError: - #Temporary until bug fixed - LOG.debug('Hit error: https://bugs.launchpad.net/bugs/1315175') - pass - - def find_resources(self, resource_query, auth_token, - endpoint_id=None, **kwargs): - """Find resources matching the query - :param resource_query: query object. Includes resource type(s) - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - :returns list of resources - """ - result = dict() - #TODO(Travis): Filter based on resource type for snapshot etc - if resource_query: - cinder_client = self.__get_cinder_client(endpoint_id, auth_token) - for resource_type in resource_query.resource_types: - cinder_resource_list = [] - if resource_type == self.volume_type: - cinder_resource_list = cinder_client.volumes.list() - elif resource_type == self.snapshot_type: - cinder_resource_list = \ - cinder_client.volume_snapshots.list() - for cinder_resource in cinder_resource_list: - if cinder_resource.status and \ - cinder_resource.status == 'available': - resource = self.transform_to_resource( - resource_type, - cinder_resource) - if resource: - result[resource.id] = resource - - return result - - def create_resource(self, resource_type, resource, auth_token, - endpoint_id=None, **kwargs): - """Create resource - :param resource_type: resource_type set for this call - :param resource: resource detail - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - raise exception.MethodNotSupported(method="create_resource") - - def delete_resource(self, resource_type, resource_id, auth_token, - endpoint_id=None, **kwargs): - """Delete resource - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - raise exception.MethodNotSupported(method="delete_resource") - - def __get_cinder_client(self, endpoint_id, auth_token): - keystone = ksclient.Client( - auth_url=cfg.CONF.keystone.auth_url, - username=cfg.CONF.keystone.username, - password=cfg.CONF.keystone.password, - tenant_name=cfg.CONF.keystone.tenant_name - ) - - cinder_public_url = None - if endpoint_id: - for entry in keystone.service_catalog.catalog.get( - 'serviceCatalog'): - for endpoint in entry['endpoints']: - if endpoint['id'] == endpoint_id: - cinder_public_url = endpoint['publicURL'] - break - if cinder_public_url: - break - else: - cinder_public_url = keystone.service_catalog.url_for( - service_type=self.service_type, - endpoint_type=self.endpoint_type - ) - - cinder_client = client.Client( - '1', - cfg.CONF.keystone.username, - cfg.CONF.keystone.password, - cfg.CONF.keystone.tenant_name, - cfg.CONF.keystone.auth_url - ) - return cinder_client - - def _get_merged_properties(self, volume): - cinder_volume_properties = {} - volume_metadata = {} - volume_image_metadata = {} - try: - volume_image_metadata = volume.volume_image_metadata - except AttributeError: - pass - try: - volume_metadata = volume.metadata - except AttributeError: - pass - cinder_volume_properties = dict(volume_metadata, - **volume_image_metadata) - return cinder_volume_properties - - def transform_to_resource(self, resource_type, volume): - - cinder_volume_properties = self._get_merged_properties(volume) - - result = Resource() - result_capabilities = [] - result.capabilities = result_capabilities - - result.id = volume.id - result.type = resource_type - #v1 / v2 clients have landmines - result.name = None - try: - result.name = volume.name - except AttributeError: - result.name = volume.display_name - - for key in cinder_volume_properties: - if key in self.unmodifiable_properties: - continue - utils.resolve_capability( - key, cinder_volume_properties[key], result) - - return result - - def replace_colon_from_name(self, name): - if name: - return name.replace(':', '#') - return - - def replace_hash_from_name(self, name): - if name: - return name.replace('#', ':') - return diff --git a/graffiti/drivers/modules/glance.py b/graffiti/drivers/modules/glance.py deleted file mode 100644 index db50ef4..0000000 --- a/graffiti/drivers/modules/glance.py +++ /dev/null @@ -1,277 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from glanceclient import Client -from graffiti.api.model.v1.capability import Capability -from graffiti.api.model.v1.property import Property -from graffiti.api.model.v1.resource import Resource -from graffiti.common import exception -from graffiti.common import utils -from graffiti.drivers import base - -import keystoneclient.v2_0.client as ksclient - -from oslo.config import cfg - - -class GlanceResourceDriver(base.ResourceInterface): - - def __init__(self): - super(GlanceResourceDriver, self).__init__() - self.separator = "." - self.service_type = 'image' - self.endpoint_type = 'publicURL' - self.default_namespace_postfix = "::Default" - self.unknown_properties_type = "AdditionalProperties" - self.unmodifiable_properties = [u'instance_uuid', u'image_type', - u'base_image_ref', u'image_location'] - - def get_resource(self, resource_type, resource_id, auth_token, - endpoint_id=None, **kwargs): - """Retrieve the resource detail - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - :returns resource detail - """ - - # glance_image_properties = { - # "GLANCE.MySQL.Port": "3605", - # "GLANCE.MySQL.Home": "/opt/mysql", - # "GLANCE.Apache.Port": "8080", - # "GLANCE.Apache.docroot": "/var/apache/static" - # } - - glance_client = self.__get_glance_client(endpoint_id, auth_token) - - image = glance_client.images.get(resource_id) - image_resource = self.transform_image_to_resource(resource_type, image) - - return image_resource - - def update_resource(self, resource_type, resource_id, resource, auth_token, - endpoint_id=None, **kwargs): - """Update resource - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param resource: resource detail - :type param: graffiti.api.model.v1.resource.Resource - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - - glance_client = self.__get_glance_client(endpoint_id, auth_token) - - image_properties = {} - for capability in resource.capabilities: - if capability.capability_type_namespace \ - == resource_type + self.default_namespace_postfix \ - and capability.capability_type \ - == self.unknown_properties_type: - # For unknown properties, just directly set property name. - for property_name, property_value in \ - capability.properties.iteritems(): - image_properties[property_name] = property_value - else: - properties = capability.properties - #capability_type = self.replace_colon_from_name( - # capability.capability_type - #) - #capability_type_namespace = self.replace_colon_from_name( - # capability.capability_type_namespace - #) - - for property_name, property_value in properties.iteritems(): - #prop_name = capability_type_namespace + \ - # self.separator + \ - # capability_type + \ - # self.separator + \ - # self.replace_colon_from_name(property_name) - prop_name = self.replace_colon_from_name(property_name) - image_properties[prop_name] = property_value - - # if capability doesnt have properties add capability as TAG - if not properties: - tag_name = capability.capability_type - image_properties[tag_name] = utils.TAG_IDENTIFIER - - #Retrieve unmodifiable properties from glance - image = glance_client.images.get(resource.id) - glance_image_properties = image.properties - merge_properties = dict() - for key in glance_image_properties: - if key in self.unmodifiable_properties: - merge_properties[key] = glance_image_properties[key] - - #Set unmodifiable properties in the glance input since purge_props=True - image_properties = dict(image_properties.items() + - merge_properties.items()) - - image.update(properties=image_properties, purge_props=True) - - def find_resources(self, resource_query, auth_token, - endpoint_id=None, **kwargs): - """Find resources matching the query - :param resource_query: query object. Includes resource type(s) - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - :returns list of resources - """ - resource_list = dict() - if resource_query: - glance_client = self.__get_glance_client( - endpoint_id, - auth_token - ) - images = glance_client.images.list() - for image in list(images): - #Filter based on requested resource types - glance_image_properties = image.properties - image_type = "OS::Glance::Image" - if "image_type" in glance_image_properties.keys(): - image_type = glance_image_properties['image_type'] - if image_type and image_type.lower() == "snapshot": - image_type = "OS::Glance::Snapshot" - - if image_type in resource_query.resource_types: - resource = self.transform_image_to_resource( - image_type, - image - ) - resource_list[resource.id] = resource - return resource_list - - def create_resource(self, resource_type, resource, auth_token, - endpoint_id=None, **kwargs): - """Create resource - :param resource_type: resource_type set for this call - :param resource: resource detail - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - raise exception.MethodNotSupported(method="create_resource") - - def delete_resource(self, resource_type, resource_id, auth_token, - endpoint_id=None, **kwargs): - """Delete resource - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - raise exception.MethodNotSupported(method="delete_resource") - - def __get_glance_client(self, endpoint_id, auth_token): - keystone = ksclient.Client( - auth_url=cfg.CONF.keystone.auth_url, - username=cfg.CONF.keystone.username, - password=cfg.CONF.keystone.password, - tenant_name=cfg.CONF.keystone.tenant_name - ) - - glance_public_url = None - if endpoint_id: - for entry in keystone.service_catalog.catalog.get( - 'serviceCatalog'): - for endpoint in entry['endpoints']: - if endpoint['id'] == endpoint_id: - glance_public_url = endpoint['publicURL'] - break - if glance_public_url: - break - else: - glance_public_url = keystone.service_catalog.url_for( - service_type=self.service_type, - endpoint_type=self.endpoint_type - ) - glance_client = Client( - '1', - endpoint=glance_public_url, - token=auth_token - ) - return glance_client - - def transform_image_to_resource(self, resource_type, image): - glance_image_properties = image.properties - image_resource = Resource() - image_capabilities = [] - image_resource.capabilities = image_capabilities - - image_resource.id = image.id - image_resource.type = resource_type - image_resource.name = image.name - - for key in glance_image_properties: - if key not in self.unmodifiable_properties: - if key.count(self.separator) == 2: - (namespace, capability_type, prop_name) = key.split(".") - namespace = self.replace_hash_from_name(namespace) - capability_type = \ - self.replace_hash_from_name(capability_type) - prop_name = self.replace_hash_from_name(prop_name) - else: - prop_name = key - capability_type = None - namespace = None - - cap_and_namespace = utils.get_qualifier( - key, - glance_image_properties[key] - ) - if cap_and_namespace: - capability_type = cap_and_namespace.name - namespace = cap_and_namespace.namespace - else: - namespace = resource_type + \ - self.default_namespace_postfix - capability_type = self.unknown_properties_type - - image_property = Property() - image_property.name = prop_name - image_property.value = glance_image_properties[key] - - image_capability = None - for capability in image_resource.capabilities: - if capability.capability_type_namespace == namespace and \ - capability.capability_type == capability_type: - image_capability = capability - - if not image_capability: - image_capability = Capability() - image_capability.properties = {} - image_resource.capabilities.append(image_capability) - - image_capability.capability_type_namespace = namespace - image_capability.capability_type = capability_type - image_capability.properties[image_property.name] = \ - image_property.value - - return image_resource - - def replace_colon_from_name(self, name): - if name: - return name.replace(':', '#') - return - - def replace_hash_from_name(self, name): - if name: - return name.replace('#', ':') - return diff --git a/graffiti/drivers/modules/local.py b/graffiti/drivers/modules/local.py deleted file mode 100644 index d802217..0000000 --- a/graffiti/drivers/modules/local.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.api.model.v1.dao.resource_dao_factory import \ - ResourceDAOFactory - -from graffiti.drivers import base - -from oslo.config import cfg - - -class LocalResourceDriver(base.ResourceInterface): - - def __init__(self): - super(LocalResourceDriver, self).__init__() - persistence_type = cfg.CONF.DEFAULT.persistence_type - - self._resource_dao = ResourceDAOFactory.create(persistence_type) - - def get_resource(self, resource_type, resource_id, auth_token, - endpoint_id=None, **kwargs): - """Retrieve the resource detail - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - :returns resource detail - """ - - res = self._resource_dao.get_resource(resource_id) - return res - - def find_resources(self, resource_query, auth_token, - endpoint_id=None, **kwargs): - """Find resources matching the query - :param resource_query: query object. Includes resource type(s) - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - :returns list of resources - """ - res_list = self._resource_dao.find_resources(resource_query) - if res_list: - return res_list - - return [] - - def create_resource(self, resource_type, resource, auth_token, - endpoint_id=None, **kwargs): - """Create resource - :param resource_type: resource_type set for this call - :param resource: resource detail - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - - id = resource.id if hasattr(resource, 'id') else None - self._resource_dao.set_resource(id, resource=resource) - - return resource - - def update_resource(self, resource_type, resource_id, resource, - auth_token, endpoint_id=None, **kwargs): - """Update resource - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param resource: resource detail - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - self._resource_dao.set_resource( - resource_id, - resource=resource - ) - return resource - - def delete_resource(self, resource_type, resource_id, auth_token, - endpoint_id=None, **kwargs): - """Delete resource - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - #TODO(Lakshmi): Implement delete - pass diff --git a/graffiti/drivers/modules/nova.py b/graffiti/drivers/modules/nova.py deleted file mode 100644 index 502470d..0000000 --- a/graffiti/drivers/modules/nova.py +++ /dev/null @@ -1,316 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.api.model.v1.capability import Capability -from graffiti.api.model.v1.resource import Resource -from graffiti.common import exception -from graffiti.common import utils -from graffiti.drivers import base - -from novaclient.v1_1 import client - -from oslo.config import cfg - - -class NovaResourceDriver(base.ResourceInterface): - - def __init__(self): - super(NovaResourceDriver, self).__init__() - self.separator = ":" - self.service_type = 'compute' - - self.endpoint_type = 'publicURL' - self.default_namespace = "OS::COMPUTE::CPU" - self.flavor_resource_type = "OS::Nova::Flavor" - self.aggregate_resource_type = "OS::Nova::Aggregate" - - def get_resource(self, resource_type, resource_id, auth_token, - endpoint_id=None, **kwargs): - """Retrieve the resource detail - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - :returns resource detail - """ - - nova_client = self.__get_nova_client(auth_token) - - nova_resource = None - if resource_type == self.flavor_resource_type: - nova_resource = nova_client.flavors.get(resource_id) - if nova_resource: - return self.transform_flavor_to_resource( - resource_type, nova_resource) - elif resource_type == self.aggregate_resource_type: - nova_resource = nova_client.aggregates.get(resource_id) - if nova_resource: - return self.transform_aggregate_to_resource( - resource_type, nova_resource) - return nova_resource - - def update_resource(self, resource_type, resource_id, resource, auth_token, - endpoint_id=None, **kwargs): - """Update resource - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param resource: resource detail - :type param: graffiti.api.model.v1.resource.Resource - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - - nova_client = self.__get_nova_client(auth_token) - - if resource_type == self.flavor_resource_type: - nova_resource = nova_client.flavors.get(resource_id) - if nova_resource: - extraspecs = self.transform_resource_to_extraspecs(resource) - nova_resource.set_keys(extraspecs) - elif resource_type == self.aggregate_resource_type: - nova_resource = nova_client.aggregates.get(resource_id) - if nova_resource: - metadata = self.transform_resource_to_aggregate(resource) - nova_resource.set_metadata(metadata) - - def find_resources(self, resource_query, auth_token, - endpoint_id=None, **kwargs): - """Find resources matching the query - :param query_string: query expression. Include resource type(s) - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - :returns list of resources - """ - resource_list = dict() - if resource_query: - nova_client = self.__get_nova_client(auth_token) - flavors = list(nova_client.flavors.list()) - for flavor in flavors: - flavor_resource = self.transform_flavor_to_resource( - self.flavor_resource_type, - flavor - ) - resource_list[flavor_resource.id] = flavor_resource - - return resource_list - - def create_resource(self, resource_type, resource, auth_token, - endpoint_id=None, **kwargs): - """Create resource - :param resource_type: resource_type set for this call - :param resource: resource detail - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - raise exception.MethodNotSupported(method="create_resource") - - def delete_resource(self, resource_type, resource_id, auth_token, - endpoint_id=None, **kwargs): - """Delete resource - :param resource_type: resource_type set for this call - :param resource_id: unique resource identifier - :param auth_token: keystone auth_token of request user - :param endpoint_id: id for locating the cloud resource provider - :param **kwargs: Include additional info required by the driver, - """ - raise exception.MethodNotSupported(method="delete_resource") - - def __get_nova_client(self, auth_token): - auth_url = cfg.CONF.keystone.auth_url - username = cfg.CONF.keystone.username - password = cfg.CONF.keystone.password - tenant_name = cfg.CONF.keystone.tenant_name - - nova_client = client.Client( - username, - password, - tenant_name, - auth_url, - service_type="compute") - - return nova_client - - def transform_aggregate_to_resource(self, resource_type, aggregate): - aggregate_resource = Resource() - aggregate_resource.id = str(aggregate.id) - aggregate_resource.name = aggregate.name - aggregate_resource.type = resource_type - - aggregate_resource.capabilities = [] - aggregate_resource.properties = {} - - aggregate_resource.properties.update( - { - "availability_zone": aggregate.availability_zone - } - ) - - for key, value in aggregate.metadata.items(): - utils.resolve_capability(key, value, aggregate_resource) - return aggregate_resource - - def transform_resource_to_aggregate(self, resource): - properties = {} - for capability in resource.capabilities: - print capability.properties - if not capability.properties: - #if capability doesnt have properties add as TAG - key = capability.capability_type - properties[key] = utils.TAG_IDENTIFIER - else: - for property_name, property_value \ - in capability.properties.items(): - key = property_name - if property_value: - properties[key] = str(property_value) - - return properties - - def transform_flavor_to_resource(self, resource_type, flavor): - flavor_resource = Resource() - flavor_resource.id = flavor.id - flavor_resource.type = resource_type - flavor_resource.name = flavor.name - - flavor_resource.capabilities = [] - flavor_resource.properties = {} - - flavor_resource.properties.update( - { - "ram": flavor.ram, - "disk": flavor.disk, - "vcpus": flavor.vcpus - } - ) - - extra_spec_keys = flavor.get_keys() - - for key in extra_spec_keys: - # capabilities:cpu_info:features= aes - # capabilities:cpu_info:vendor=Intel - # capabilities:cpu_info:topology:cores=2 - # ssd = true - # cap {ct:aes, properties {name:features, value:aes}} - # cap {ct:Intel, properties {name:vendor, value:Intel}} - # cap {ct:cores, properties {name:topology:cores, value=2}} - # cap {ct:sst, properties {name:ssd, value:true}} - - def splitFeatures(features): - import re - features = features.split() - l = [v for v in features if not re.match("<(.*)>", v)] - return l - - def extractFeatureValue(key, value): - splited_key = key.split(':') - splited_value = splitFeatures(value) - - c_name = splited_value[0] - p_name = splited_key[-1] - p_value = splited_value[0] - return (c_name, p_name, p_value) - - def extractTopologyValue(key, value): - splited = key.split(':') - c_name = splited[-1] - p_name = splited[-1] - p_value = value - return (c_name, p_name, p_value) - - def extractSimpleValue(key, value): - splited = key.split(':') - c_name = value - p_name = splited[-1] - p_value = value - return (c_name, p_name, p_value) - - extraspecs_key_map = { - "capabilities:cpu_info:features": extractFeatureValue, - "capabilities:cpu_info:topology:cores": extractTopologyValue, - "capabilities:cpu_info:topology:sockets": extractTopologyValue, - "capabilities:cpu_info:topology:threads": extractTopologyValue, - } - - capability_namespace = self.default_namespace - capability_type = None - property_name = None - property_value = None - - if not key.startswith("capabilities:cpu_info"): - utils.resolve_capability( - key, extra_spec_keys[key], flavor_resource) - else: - #TODO(Facundo)This can be automatic using dictionary - if key in extraspecs_key_map: - capability_type, property_name, property_value = \ - extraspecs_key_map[key](key, extra_spec_keys[key]) - else: - capability_type, property_name, property_value = \ - extractSimpleValue(key, extra_spec_keys[key]) - - capability = Capability() - capability.capability_type_namespace = capability_namespace - capability.capability_type = capability_type - capability.properties = {property_name: property_value} - - flavor_resource.capabilities.append(capability) - - return flavor_resource - - def transform_resource_to_extraspecs(self, resource): - - topology_properties = { - "cores": "topology:cores", - "threads": "topology:threads", - "sockets": "topology:sockets", - } - - extraspec = {} - - for capability in resource.capabilities: - - base_key = "" - if capability.capability_type_namespace == self.default_namespace: - base_key = "capabilities:cpu_info" - - for property_name, property_value \ - in capability.properties.items(): - if property_name == "features": - key = base_key + ':' + property_name - extraspec[key] = ' ' + str(property_value) - continue - if property_name in topology_properties: - key = base_key + ':' \ - + topology_properties[property_name] - extraspec[key] = str(property_value) - continue - key = base_key + ':' + property_name - extraspec[key] = str(property_value) - else: - if not capability.properties: - #if capability doesnt have properties add as TAG - key = capability.capability_type - extraspec[key] = utils.TAG_IDENTIFIER - else: - for property_name, property_value \ - in capability.properties.items(): - key = property_name - extraspec[key] = str(property_value) - - return extraspec diff --git a/graffiti/drivers/nova.py b/graffiti/drivers/nova.py deleted file mode 100644 index 61b6b11..0000000 --- a/graffiti/drivers/nova.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from graffiti.drivers import base -from graffiti.drivers.modules import nova - - -class NovaResourceDriver(base.BaseDriver): - """This driver implements nova-compute resource driver interface - """ - - def __init__(self): - self.resource = nova.NovaResourceDriver() - self.resource_types = ["OS::Nova::Flavor", "OS::Nova::Aggregate"] - - def get_resource_types(self): - """Returns the resource types supported by the implementing driver - :returns [str] List of resource type strings - """ - return self.resource_types diff --git a/graffiti/openstack/__init__.py b/graffiti/openstack/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/openstack/common/__init__.py b/graffiti/openstack/common/__init__.py deleted file mode 100644 index 2a00f3b..0000000 --- a/graffiti/openstack/common/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -import six -six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox')) diff --git a/graffiti/openstack/common/context.py b/graffiti/openstack/common/context.py deleted file mode 100644 index 09019ee..0000000 --- a/graffiti/openstack/common/context.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# 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. - -""" -Simple class that stores security context information in the web request. - -Projects should subclass this class if they wish to enhance the request -context or provide additional information in their specific WSGI pipeline. -""" - -import itertools -import uuid - - -def generate_request_id(): - return 'req-%s' % str(uuid.uuid4()) - - -class RequestContext(object): - - """Helper class to represent useful information about a request context. - - Stores information about the security context under which the user - accesses the system, as well as additional request information. - """ - - user_idt_format = '{user} {tenant} {domain} {user_domain} {p_domain}' - - def __init__(self, auth_token=None, user=None, tenant=None, domain=None, - user_domain=None, project_domain=None, is_admin=False, - read_only=False, show_deleted=False, request_id=None, - instance_uuid=None): - self.auth_token = auth_token - self.user = user - self.tenant = tenant - self.domain = domain - self.user_domain = user_domain - self.project_domain = project_domain - self.is_admin = is_admin - self.read_only = read_only - self.show_deleted = show_deleted - self.instance_uuid = instance_uuid - if not request_id: - request_id = generate_request_id() - self.request_id = request_id - - def to_dict(self): - user_idt = ( - self.user_idt_format.format(user=self.user or '-', - tenant=self.tenant or '-', - domain=self.domain or '-', - user_domain=self.user_domain or '-', - p_domain=self.project_domain or '-')) - - return {'user': self.user, - 'tenant': self.tenant, - 'domain': self.domain, - 'user_domain': self.user_domain, - 'project_domain': self.project_domain, - 'is_admin': self.is_admin, - 'read_only': self.read_only, - 'show_deleted': self.show_deleted, - 'auth_token': self.auth_token, - 'request_id': self.request_id, - 'instance_uuid': self.instance_uuid, - 'user_identity': user_idt} - - -def get_admin_context(show_deleted=False): - context = RequestContext(None, - tenant=None, - is_admin=True, - show_deleted=show_deleted) - return context - - -def get_context_from_function_and_args(function, args, kwargs): - """Find an arg of type RequestContext and return it. - - This is useful in a couple of decorators where we don't - know much about the function we're wrapping. - """ - - for arg in itertools.chain(kwargs.values(), args): - if isinstance(arg, RequestContext): - return arg - - return None - - -def is_user_context(context): - """Indicates if the request context is a normal user.""" - if not context: - return False - if context.is_admin: - return False - if not context.user_id or not context.project_id: - return False - return True diff --git a/graffiti/openstack/common/db/__init__.py b/graffiti/openstack/common/db/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/openstack/common/db/api.py b/graffiti/openstack/common/db/api.py deleted file mode 100644 index 64b224b..0000000 --- a/graffiti/openstack/common/db/api.py +++ /dev/null @@ -1,162 +0,0 @@ -# Copyright (c) 2013 Rackspace Hosting -# All Rights Reserved. -# -# 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. - -"""Multiple DB API backend support. - -A DB backend module should implement a method named 'get_backend' which -takes no arguments. The method can return any object that implements DB -API methods. -""" - -import functools -import logging -import threading -import time - -from graffiti.openstack.common.db import exception -from graffiti.openstack.common.gettextutils import _LE -from graffiti.openstack.common import importutils - - -LOG = logging.getLogger(__name__) - - -def safe_for_db_retry(f): - """Enable db-retry for decorated function, if config option enabled.""" - f.__dict__['enable_retry'] = True - return f - - -class wrap_db_retry(object): - """Retry db.api methods, if DBConnectionError() raised - - Retry decorated db.api methods. If we enabled `use_db_reconnect` - in config, this decorator will be applied to all db.api functions, - marked with @safe_for_db_retry decorator. - Decorator catchs DBConnectionError() and retries function in a - loop until it succeeds, or until maximum retries count will be reached. - """ - - def __init__(self, retry_interval, max_retries, inc_retry_interval, - max_retry_interval): - super(wrap_db_retry, self).__init__() - - self.retry_interval = retry_interval - self.max_retries = max_retries - self.inc_retry_interval = inc_retry_interval - self.max_retry_interval = max_retry_interval - - def __call__(self, f): - @functools.wraps(f) - def wrapper(*args, **kwargs): - next_interval = self.retry_interval - remaining = self.max_retries - - while True: - try: - return f(*args, **kwargs) - except exception.DBConnectionError as e: - if remaining == 0: - LOG.exception(_LE('DB exceeded retry limit.')) - raise exception.DBError(e) - if remaining != -1: - remaining -= 1 - LOG.exception(_LE('DB connection error.')) - # NOTE(vsergeyev): We are using patched time module, so - # this effectively yields the execution - # context to another green thread. - time.sleep(next_interval) - if self.inc_retry_interval: - next_interval = min( - next_interval * 2, - self.max_retry_interval - ) - return wrapper - - -class DBAPI(object): - def __init__(self, backend_name, backend_mapping=None, lazy=False, - **kwargs): - """Initialize the chosen DB API backend. - - :param backend_name: name of the backend to load - :type backend_name: str - - :param backend_mapping: backend name -> module/class to load mapping - :type backend_mapping: dict - - :param lazy: load the DB backend lazily on the first DB API method call - :type lazy: bool - - Keyword arguments: - - :keyword use_db_reconnect: retry DB transactions on disconnect or not - :type use_db_reconnect: bool - - :keyword retry_interval: seconds between transaction retries - :type retry_interval: int - - :keyword inc_retry_interval: increase retry interval or not - :type inc_retry_interval: bool - - :keyword max_retry_interval: max interval value between retries - :type max_retry_interval: int - - :keyword max_retries: max number of retries before an error is raised - :type max_retries: int - - """ - - self._backend = None - self._backend_name = backend_name - self._backend_mapping = backend_mapping or {} - self._lock = threading.Lock() - - if not lazy: - self._load_backend() - - self.use_db_reconnect = kwargs.get('use_db_reconnect', False) - self.retry_interval = kwargs.get('retry_interval', 1) - self.inc_retry_interval = kwargs.get('inc_retry_interval', True) - self.max_retry_interval = kwargs.get('max_retry_interval', 10) - self.max_retries = kwargs.get('max_retries', 20) - - def _load_backend(self): - with self._lock: - if not self._backend: - # Import the untranslated name if we don't have a mapping - backend_path = self._backend_mapping.get(self._backend_name, - self._backend_name) - backend_mod = importutils.import_module(backend_path) - self._backend = backend_mod.get_backend() - - def __getattr__(self, key): - if not self._backend: - self._load_backend() - - attr = getattr(self._backend, key) - if not hasattr(attr, '__call__'): - return attr - # NOTE(vsergeyev): If `use_db_reconnect` option is set to True, retry - # DB API methods, decorated with @safe_for_db_retry - # on disconnect. - if self.use_db_reconnect and hasattr(attr, 'enable_retry'): - attr = wrap_db_retry( - retry_interval=self.retry_interval, - max_retries=self.max_retries, - inc_retry_interval=self.inc_retry_interval, - max_retry_interval=self.max_retry_interval)(attr) - - return attr diff --git a/graffiti/openstack/common/db/exception.py b/graffiti/openstack/common/db/exception.py deleted file mode 100644 index de97583..0000000 --- a/graffiti/openstack/common/db/exception.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# 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. - -"""DB related custom exceptions.""" - -import six - -from graffiti.openstack.common.gettextutils import _ - - -class DBError(Exception): - """Wraps an implementation specific exception.""" - def __init__(self, inner_exception=None): - self.inner_exception = inner_exception - super(DBError, self).__init__(six.text_type(inner_exception)) - - -class DBDuplicateEntry(DBError): - """Wraps an implementation specific exception.""" - def __init__(self, columns=[], inner_exception=None): - self.columns = columns - super(DBDuplicateEntry, self).__init__(inner_exception) - - -class DBDeadlock(DBError): - def __init__(self, inner_exception=None): - super(DBDeadlock, self).__init__(inner_exception) - - -class DBInvalidUnicodeParameter(Exception): - message = _("Invalid Parameter: " - "Unicode is not supported by the current database.") - - -class DbMigrationError(DBError): - """Wraps migration_graffiti specific exception.""" - def __init__(self, message=None): - super(DbMigrationError, self).__init__(message) - - -class DBConnectionError(DBError): - """Wraps connection specific exception.""" - pass diff --git a/graffiti/openstack/common/db/options.py b/graffiti/openstack/common/db/options.py deleted file mode 100644 index 45aa294..0000000 --- a/graffiti/openstack/common/db/options.py +++ /dev/null @@ -1,171 +0,0 @@ -# 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. - -import copy - -from oslo.config import cfg - - -database_opts = [ - cfg.StrOpt('sqlite_db', - deprecated_group='DEFAULT', - default='graffiti.sqlite', - help='The file name to use with SQLite'), - cfg.BoolOpt('sqlite_synchronous', - deprecated_group='DEFAULT', - default=True, - help='If True, SQLite uses synchronous mode'), - cfg.StrOpt('backend', - default='sqlalchemy', - deprecated_name='db_backend', - deprecated_group='DEFAULT', - help='The backend to use for db'), - cfg.StrOpt('connection', - help='The SQLAlchemy connection string used to connect to the ' - 'database', - secret=True, - deprecated_opts=[cfg.DeprecatedOpt('sql_connection', - group='DEFAULT'), - cfg.DeprecatedOpt('sql_connection', - group='DATABASE'), - cfg.DeprecatedOpt('connection', - group='sql'), ]), - cfg.StrOpt('mysql_sql_mode', - default='TRADITIONAL', - help='The SQL mode to be used for MySQL sessions. ' - 'This option, including the default, overrides any ' - 'server-set SQL mode. To use whatever SQL mode ' - 'is set by the server configuration, ' - 'set this to no value. Example: mysql_sql_mode='), - cfg.IntOpt('idle_timeout', - default=3600, - deprecated_opts=[cfg.DeprecatedOpt('sql_idle_timeout', - group='DEFAULT'), - cfg.DeprecatedOpt('sql_idle_timeout', - group='DATABASE'), - cfg.DeprecatedOpt('idle_timeout', - group='sql')], - help='Timeout before idle sql connections are reaped'), - cfg.IntOpt('min_pool_size', - default=1, - deprecated_opts=[cfg.DeprecatedOpt('sql_min_pool_size', - group='DEFAULT'), - cfg.DeprecatedOpt('sql_min_pool_size', - group='DATABASE')], - help='Minimum number of SQL connections to keep open in a ' - 'pool'), - cfg.IntOpt('max_pool_size', - default=None, - deprecated_opts=[cfg.DeprecatedOpt('sql_max_pool_size', - group='DEFAULT'), - cfg.DeprecatedOpt('sql_max_pool_size', - group='DATABASE')], - help='Maximum number of SQL connections to keep open in a ' - 'pool'), - cfg.IntOpt('max_retries', - default=10, - deprecated_opts=[cfg.DeprecatedOpt('sql_max_retries', - group='DEFAULT'), - cfg.DeprecatedOpt('sql_max_retries', - group='DATABASE')], - help='Maximum db connection retries during startup. ' - '(setting -1 implies an infinite retry count)'), - cfg.IntOpt('retry_interval', - default=10, - deprecated_opts=[cfg.DeprecatedOpt('sql_retry_interval', - group='DEFAULT'), - cfg.DeprecatedOpt('reconnect_interval', - group='DATABASE')], - help='Interval between retries of opening a sql connection'), - cfg.IntOpt('max_overflow', - default=None, - deprecated_opts=[cfg.DeprecatedOpt('sql_max_overflow', - group='DEFAULT'), - cfg.DeprecatedOpt('sqlalchemy_max_overflow', - group='DATABASE')], - help='If set, use this value for max_overflow with sqlalchemy'), - cfg.IntOpt('connection_debug', - default=0, - deprecated_opts=[cfg.DeprecatedOpt('sql_connection_debug', - group='DEFAULT')], - help='Verbosity of SQL debugging information. 0=None, ' - '100=Everything'), - cfg.BoolOpt('connection_trace', - default=False, - deprecated_opts=[cfg.DeprecatedOpt('sql_connection_trace', - group='DEFAULT')], - help='Add python stack traces to SQL as comment strings'), - cfg.IntOpt('pool_timeout', - default=None, - deprecated_opts=[cfg.DeprecatedOpt('sqlalchemy_pool_timeout', - group='DATABASE')], - help='If set, use this value for pool_timeout with sqlalchemy'), - cfg.BoolOpt('use_db_reconnect', - default=False, - help='Enable the experimental use of database reconnect ' - 'on connection lost'), - cfg.IntOpt('db_retry_interval', - default=1, - help='seconds between db connection retries'), - cfg.BoolOpt('db_inc_retry_interval', - default=True, - help='Whether to increase interval between db connection ' - 'retries, up to db_max_retry_interval'), - cfg.IntOpt('db_max_retry_interval', - default=10, - help='max seconds between db connection retries, if ' - 'db_inc_retry_interval is enabled'), - cfg.IntOpt('db_max_retries', - default=20, - help='maximum db connection retries before error is raised. ' - '(setting -1 implies an infinite retry count)'), -] - -CONF = cfg.CONF -CONF.register_opts(database_opts, 'database') - - -def set_defaults(sql_connection, sqlite_db, max_pool_size=None, - max_overflow=None, pool_timeout=None): - """Set defaults for configuration variables.""" - cfg.set_defaults(database_opts, - connection=sql_connection, - sqlite_db=sqlite_db) - # Update the QueuePool defaults - if max_pool_size is not None: - cfg.set_defaults(database_opts, - max_pool_size=max_pool_size) - if max_overflow is not None: - cfg.set_defaults(database_opts, - max_overflow=max_overflow) - if pool_timeout is not None: - cfg.set_defaults(database_opts, - pool_timeout=pool_timeout) - - -def list_opts(): - """Returns a list of oslo.config options available in the library. - - The returned list includes all oslo.config options which may be registered - at runtime by the library. - - Each element of the list is a tuple. The first element is the name of the - group under which the list of elements in the second element will be - registered. A group name of None corresponds to the [DEFAULT] group in - config files. - - The purpose of this is to allow tools like the Oslo sample config file - generator to discover the options exposed to users by this library. - - :returns: a list of (group_name, opts) tuples - """ - return [('database', copy.deepcopy(database_opts))] diff --git a/graffiti/openstack/common/db/sqlalchemy/__init__.py b/graffiti/openstack/common/db/sqlalchemy/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/openstack/common/db/sqlalchemy/migration.py b/graffiti/openstack/common/db/sqlalchemy/migration.py deleted file mode 100644 index d8935a3..0000000 --- a/graffiti/openstack/common/db/sqlalchemy/migration.py +++ /dev/null @@ -1,268 +0,0 @@ -# coding: utf-8 -# -# Copyright (c) 2013 OpenStack Foundation -# All Rights Reserved. -# -# 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. -# -# Base on code in migrate/changeset/databases/sqlite.py which is under -# the following license: -# -# The MIT License -# -# Copyright (c) 2009 Evan Rosson, Jan Dittberner, Domen Kožar -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import os -import re - -from migrate.changeset import ansisql -from migrate.changeset.databases import sqlite -from migrate import exceptions as versioning_exceptions -from migrate.versioning import api as versioning_api -from migrate.versioning.repository import Repository -import sqlalchemy -from sqlalchemy.schema import UniqueConstraint - -from graffiti.openstack.common.db import exception -from graffiti.openstack.common.gettextutils import _ - - -def _get_unique_constraints(self, table): - """Retrieve information about existing unique constraints of the table - - This feature is needed for _recreate_table() to work properly. - Unfortunately, it's not available in sqlalchemy 0.7.x/0.8.x. - - """ - - data = table.metadata.bind.execute( - """SELECT sql - FROM sqlite_master - WHERE - type='table' AND - name=:table_name""", - table_name=table.name - ).fetchone()[0] - - UNIQUE_PATTERN = "CONSTRAINT (\w+) UNIQUE \(([^\)]+)\)" - return [ - UniqueConstraint( - *[getattr(table.columns, c.strip(' "')) for c in cols.split(",")], - name=name - ) - for name, cols in re.findall(UNIQUE_PATTERN, data) - ] - - -def _recreate_table(self, table, column=None, delta=None, omit_uniques=None): - """Recreate the table properly - - Unlike the corresponding original method of sqlalchemy-migrate this one - doesn't drop existing unique constraints when creating a new one. - - """ - - table_name = self.preparer.format_table(table) - - # we remove all indexes so as not to have - # problems during copy and re-create - for index in table.indexes: - index.drop() - - # reflect existing unique constraints - for uc in self._get_unique_constraints(table): - table.append_constraint(uc) - # omit given unique constraints when creating a new table if required - table.constraints = set([ - cons for cons in table.constraints - if omit_uniques is None or cons.name not in omit_uniques - ]) - - self.append('ALTER TABLE %s RENAME TO migration_tmp' % table_name) - self.execute() - - insertion_string = self._modify_table(table, column, delta) - - table.create(bind=self.connection) - self.append(insertion_string % {'table_name': table_name}) - self.execute() - self.append('DROP TABLE migration_tmp') - self.execute() - - -def _visit_migrate_unique_constraint(self, *p, **k): - """Drop the given unique constraint - - The corresponding original method of sqlalchemy-migrate just - raises NotImplemented error - - """ - - self.recreate_table(p[0].table, omit_uniques=[p[0].name]) - - -def patch_migrate(): - """A workaround for SQLite's inability to alter things - - SQLite abilities to alter tables are very limited (please read - http://www.sqlite.org/lang_altertable.html for more details). - E. g. one can't drop a column or a constraint in SQLite. The - workaround for this is to recreate the original table omitting - the corresponding constraint (or column). - - sqlalchemy-migrate library has recreate_table() method that - implements this workaround, but it does it wrong: - - - information about unique constraints of a table - is not retrieved. So if you have a table with one - unique constraint and a migration_graffit adding another one - you will end up with a table that has only the - latter unique constraint, and the former will be lost - - - dropping of unique constraints is not supported at all - - The proper way to fix this is to provide a pull-request to - sqlalchemy-migrate, but the project seems to be dead. So we - can go on with monkey-patching of the lib at least for now. - - """ - - # this patch is needed to ensure that recreate_table() doesn't drop - # existing unique constraints of the table when creating a new one - helper_cls = sqlite.SQLiteHelper - helper_cls.recreate_table = _recreate_table - helper_cls._get_unique_constraints = _get_unique_constraints - - # this patch is needed to be able to drop existing unique constraints - constraint_cls = sqlite.SQLiteConstraintDropper - constraint_cls.visit_migrate_unique_constraint = \ - _visit_migrate_unique_constraint - constraint_cls.__bases__ = (ansisql.ANSIColumnDropper, - sqlite.SQLiteConstraintGenerator) - - -def db_sync(engine, abs_path, version=None, init_version=0): - """Upgrade or downgrade a database. - - Function runs the upgrade() or downgrade() functions in change scripts. - - :param engine: SQLAlchemy engine instance for a given database - :param abs_path: Absolute path to migrate repository. - :param version: Database will upgrade/downgrade until this version. - If None - database will update to the latest - available version. - :param init_version: Initial database version - """ - if version is not None: - try: - version = int(version) - except ValueError: - raise exception.DbMigrationError( - message=_("version should be an integer")) - - current_version = db_version(engine, abs_path, init_version) - repository = _find_migrate_repo(abs_path) - _db_schema_sanity_check(engine) - if version is None or version > current_version: - return versioning_api.upgrade(engine, repository, version) - else: - return versioning_api.downgrade(engine, repository, - version) - - -def _db_schema_sanity_check(engine): - """Ensure all database tables were created with required parameters. - - :param engine: SQLAlchemy engine instance for a given database - - """ - - if engine.name == 'mysql': - onlyutf8_sql = ('SELECT TABLE_NAME,TABLE_COLLATION ' - 'from information_schema.TABLES ' - 'where TABLE_SCHEMA=%s and ' - 'TABLE_COLLATION NOT LIKE "%%utf8%%"') - - table_names = [res[0] for res in engine.execute(onlyutf8_sql, - engine.url.database)] - if len(table_names) > 0: - raise ValueError(_('Tables "%s" have non utf8 collation, ' - 'please make sure all tables are CHARSET=utf8' - ) % ','.join(table_names)) - - -def db_version(engine, abs_path, init_version): - """Show the current version of the repository. - - :param engine: SQLAlchemy engine instance for a given database - :param abs_path: Absolute path to migrate repository - :param version: Initial database version - """ - repository = _find_migrate_repo(abs_path) - try: - return versioning_api.db_version(engine, repository) - except versioning_exceptions.DatabaseNotControlledError: - meta = sqlalchemy.MetaData() - meta.reflect(bind=engine) - tables = meta.tables - if len(tables) == 0 or 'alembic_version' in tables: - db_version_control(engine, abs_path, version=init_version) - return versioning_api.db_version(engine, repository) - else: - raise exception.DbMigrationError( - message=_( - "The database is not under version control, but has " - "tables. Please stamp the current version of the schema " - "manually.")) - - -def db_version_control(engine, abs_path, version=None): - """Mark a database as under this repository's version control. - - Once a database is under version control, schema changes should - only be done via change scripts in this repository. - - :param engine: SQLAlchemy engine instance for a given database - :param abs_path: Absolute path to migrate repository - :param version: Initial database version - """ - repository = _find_migrate_repo(abs_path) - versioning_api.version_control(engine, repository, version) - return version - - -def _find_migrate_repo(abs_path): - """Get the project's change script repository - - :param abs_path: Absolute path to migrate repository - """ - if not os.path.exists(abs_path): - raise exception.DbMigrationError("Path %s not found" % abs_path) - return Repository(abs_path) diff --git a/graffiti/openstack/common/db/sqlalchemy/models.py b/graffiti/openstack/common/db/sqlalchemy/models.py deleted file mode 100644 index 74915fd..0000000 --- a/graffiti/openstack/common/db/sqlalchemy/models.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (c) 2011 X.commerce, a business unit of eBay Inc. -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# Copyright 2011 Piston Cloud Computing, Inc. -# Copyright 2012 Cloudscaling Group, Inc. -# All Rights Reserved. -# -# 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. -""" -SQLAlchemy models. -""" - -import six - -from sqlalchemy import Column, Integer -from sqlalchemy import DateTime -from sqlalchemy.orm import object_mapper - -from graffiti.openstack.common import timeutils - - -class ModelBase(object): - """Base class for models.""" - __table_initialized__ = False - - def save(self, session): - """Save this object.""" - - # NOTE(boris-42): This part of code should be look like: - # session.add(self) - # session.flush() - # But there is a bug in sqlalchemy and eventlet that - # raises NoneType exception if there is no running - # transaction and rollback is called. As long as - # sqlalchemy has this bug we have to create transaction - # explicitly. - with session.begin(subtransactions=True): - session.add(self) - session.flush() - - def __setitem__(self, key, value): - setattr(self, key, value) - - def __getitem__(self, key): - return getattr(self, key) - - def get(self, key, default=None): - return getattr(self, key, default) - - @property - def _extra_keys(self): - """Specifies custom fields - - Subclasses can override this property to return a list - of custom fields that should be included in their dict - representation. - - For reference check tests/db/sqlalchemy/test_models.py - """ - return [] - - def __iter__(self): - columns = dict(object_mapper(self).columns).keys() - # NOTE(russellb): Allow models to specify other keys that can be looked - # up, beyond the actual db columns. An example would be the 'name' - # property for an Instance. - columns.extend(self._extra_keys) - self._i = iter(columns) - return self - - def next(self): - n = six.advance_iterator(self._i) - return n, getattr(self, n) - - def update(self, values): - """Make the model object behave like a dict.""" - for k, v in six.iteritems(values): - setattr(self, k, v) - - def iteritems(self): - """Make the model object behave like a dict. - - Includes attributes from joins. - """ - local = dict(self) - joined = dict([(k, v) for k, v in six.iteritems(self.__dict__) - if not k[0] == '_']) - local.update(joined) - return six.iteritems(local) - - -class TimestampMixin(object): - created_at = Column(DateTime, default=lambda: timeutils.utcnow()) - updated_at = Column(DateTime, onupdate=lambda: timeutils.utcnow()) - - -class SoftDeleteMixin(object): - deleted_at = Column(DateTime) - deleted = Column(Integer, default=0) - - def soft_delete(self, session): - """Mark this object as deleted.""" - self.deleted = self.id - self.deleted_at = timeutils.utcnow() - self.save(session=session) diff --git a/graffiti/openstack/common/db/sqlalchemy/provision.py b/graffiti/openstack/common/db/sqlalchemy/provision.py deleted file mode 100644 index b428627..0000000 --- a/graffiti/openstack/common/db/sqlalchemy/provision.py +++ /dev/null @@ -1,187 +0,0 @@ -# Copyright 2013 Mirantis.inc -# All Rights Reserved. -# -# 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. - -"""Provision test environment for specific DB backends""" - -import argparse -import os -import random -import string - -from six import moves -import sqlalchemy - -from graffiti.openstack.common.db import exception as exc - - -SQL_CONNECTION = os.getenv('OS_TEST_DBAPI_ADMIN_CONNECTION', 'sqlite://') - - -def _gen_credentials(*names): - """Generate credentials.""" - auth_dict = {} - for name in names: - val = ''.join(random.choice(string.ascii_lowercase) - for i in moves.range(10)) - auth_dict[name] = val - return auth_dict - - -def _get_engine(uri=SQL_CONNECTION): - """Engine creation - - By default the uri is SQL_CONNECTION which is admin credentials. - Call the function without arguments to get admin connection. Admin - connection required to create temporary user and database for each - particular test. Otherwise use existing connection to recreate connection - to the temporary database. - """ - return sqlalchemy.create_engine(uri, poolclass=sqlalchemy.pool.NullPool) - - -def _execute_sql(engine, sql, driver): - """Initialize connection, execute sql query and close it.""" - try: - with engine.connect() as conn: - if driver == 'postgresql': - conn.connection.set_isolation_level(0) - for s in sql: - conn.execute(s) - except sqlalchemy.exc.OperationalError: - msg = ('%s does not match database admin ' - 'credentials or database does not exist.') - raise exc.DBConnectionError(msg % SQL_CONNECTION) - - -def create_database(engine): - """Provide temporary user and database for each particular test.""" - driver = engine.name - - auth = _gen_credentials('database', 'user', 'passwd') - - sqls = { - 'mysql': [ - "drop database if exists %(database)s;", - "grant all on %(database)s.* to '%(user)s'@'localhost'" - " identified by '%(passwd)s';", - "create database %(database)s;", - ], - 'postgresql': [ - "drop database if exists %(database)s;", - "drop user if exists %(user)s;", - "create user %(user)s with password '%(passwd)s';", - "create database %(database)s owner %(user)s;", - ] - } - - if driver == 'sqlite': - return 'sqlite:////tmp/%s' % auth['database'] - - try: - sql_rows = sqls[driver] - except KeyError: - raise ValueError('Unsupported RDBMS %s' % driver) - sql_query = map(lambda x: x % auth, sql_rows) - - _execute_sql(engine, sql_query, driver) - - params = auth.copy() - params['backend'] = driver - return "%(backend)s://%(user)s:%(passwd)s@localhost/%(database)s" % params - - -def drop_database(engine, current_uri): - """Drop temporary database and user after each particular test.""" - engine = _get_engine(current_uri) - admin_engine = _get_engine() - driver = engine.name - auth = {'database': engine.url.database, 'user': engine.url.username} - - if driver == 'sqlite': - try: - os.remove(auth['database']) - except OSError: - pass - return - - sqls = { - 'mysql': [ - "drop database if exists %(database)s;", - "drop user '%(user)s'@'localhost';", - ], - 'postgresql': [ - "drop database if exists %(database)s;", - "drop user if exists %(user)s;", - ] - } - - try: - sql_rows = sqls[driver] - except KeyError: - raise ValueError('Unsupported RDBMS %s' % driver) - sql_query = map(lambda x: x % auth, sql_rows) - - _execute_sql(admin_engine, sql_query, driver) - - -def main(): - """Controller to handle commands - - ::create: Create test user and database with random names. - ::drop: Drop user and database created by previous command. - """ - parser = argparse.ArgumentParser( - description='Controller to handle database creation and dropping' - ' commands.', - epilog='Under normal circumstances is not used directly.' - ' Used in .testr.conf to automate test database creation' - ' and dropping processes.') - subparsers = parser.add_subparsers( - help='Subcommands to manipulate temporary test databases.') - - create = subparsers.add_parser( - 'create', - help='Create temporary test ' - 'databases and users.') - create.set_defaults(which='create') - create.add_argument( - 'instances_count', - type=int, - help='Number of databases to create.') - - drop = subparsers.add_parser( - 'drop', - help='Drop temporary test databases and users.') - drop.set_defaults(which='drop') - drop.add_argument( - 'instances', - nargs='+', - help='List of databases uri to be dropped.') - - args = parser.parse_args() - - engine = _get_engine() - which = args.which - - if which == "create": - for i in range(int(args.instances_count)): - print(create_database(engine)) - elif which == "drop": - for db in args.instances: - drop_database(engine, db) - - -if __name__ == "__main__": - main() diff --git a/graffiti/openstack/common/db/sqlalchemy/session.py b/graffiti/openstack/common/db/sqlalchemy/session.py deleted file mode 100644 index d2d1779..0000000 --- a/graffiti/openstack/common/db/sqlalchemy/session.py +++ /dev/null @@ -1,892 +0,0 @@ -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# 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. - -"""Session Handling for SQLAlchemy backend. - -Recommended ways to use sessions within this framework: - -* Don't use them explicitly; this is like running with ``AUTOCOMMIT=1``. - `model_query()` will implicitly use a session when called without one - supplied. This is the ideal situation because it will allow queries - to be automatically retried if the database connection is interrupted. - - .. note:: Automatic retry will be enabled in a future patch. - - It is generally fine to issue several queries in a row like this. Even though - they may be run in separate transactions and/or separate sessions, each one - will see the data from the prior calls. If needed, undo- or rollback-like - functionality should be handled at a logical level. For an example, look at - the code around quotas and `reservation_rollback()`. - - Examples: - - .. code:: python - - def get_foo(context, foo): - return (model_query(context, models.Foo). - filter_by(foo=foo). - first()) - - def update_foo(context, id, newfoo): - (model_query(context, models.Foo). - filter_by(id=id). - update({'foo': newfoo})) - - def create_foo(context, values): - foo_ref = models.Foo() - foo_ref.update(values) - foo_ref.save() - return foo_ref - - -* Within the scope of a single method, keep all the reads and writes within - the context managed by a single session. In this way, the session's - `__exit__` handler will take care of calling `flush()` and `commit()` for - you. If using this approach, you should not explicitly call `flush()` or - `commit()`. Any error within the context of the session will cause the - session to emit a `ROLLBACK`. Database errors like `IntegrityError` will be - raised in `session`'s `__exit__` handler, and any try/except within the - context managed by `session` will not be triggered. And catching other - non-database errors in the session will not trigger the ROLLBACK, so - exception handlers should always be outside the session, unless the - developer wants to do a partial commit on purpose. If the connection is - dropped before this is possible, the database will implicitly roll back the - transaction. - - .. note:: Statements in the session scope will not be automatically retried. - - If you create models within the session, they need to be added, but you - do not need to call `model.save()`: - - .. code:: python - - def create_many_foo(context, foos): - session = sessionmaker() - with session.begin(): - for foo in foos: - foo_ref = models.Foo() - foo_ref.update(foo) - session.add(foo_ref) - - def update_bar(context, foo_id, newbar): - session = sessionmaker() - with session.begin(): - foo_ref = (model_query(context, models.Foo, session). - filter_by(id=foo_id). - first()) - (model_query(context, models.Bar, session). - filter_by(id=foo_ref['bar_id']). - update({'bar': newbar})) - - .. note:: `update_bar` is a trivially simple example of using - ``with session.begin``. Whereas `create_many_foo` is a good example of - when a transaction is needed, it is always best to use as few queries as - possible. - - The two queries in `update_bar` can be better expressed using a single query - which avoids the need for an explicit transaction. It can be expressed like - so: - - .. code:: python - - def update_bar(context, foo_id, newbar): - subq = (model_query(context, models.Foo.id). - filter_by(id=foo_id). - limit(1). - subquery()) - (model_query(context, models.Bar). - filter_by(id=subq.as_scalar()). - update({'bar': newbar})) - - For reference, this emits approximately the following SQL statement: - - .. code:: sql - - UPDATE bar SET bar = ${newbar} - WHERE id=(SELECT bar_id FROM foo WHERE id = ${foo_id} LIMIT 1); - - .. note:: `create_duplicate_foo` is a trivially simple example of catching an - exception while using ``with session.begin``. Here create two duplicate - instances with same primary key, must catch the exception out of context - managed by a single session: - - .. code:: python - - def create_duplicate_foo(context): - foo1 = models.Foo() - foo2 = models.Foo() - foo1.id = foo2.id = 1 - session = sessionmaker() - try: - with session.begin(): - session.add(foo1) - session.add(foo2) - except exception.DBDuplicateEntry as e: - handle_error(e) - -* Passing an active session between methods. Sessions should only be passed - to private methods. The private method must use a subtransaction; otherwise - SQLAlchemy will throw an error when you call `session.begin()` on an existing - transaction. Public methods should not accept a session parameter and should - not be involved in sessions within the caller's scope. - - Note that this incurs more overhead in SQLAlchemy than the above means - due to nesting transactions, and it is not possible to implicitly retry - failed database operations when using this approach. - - This also makes code somewhat more difficult to read and debug, because a - single database transaction spans more than one method. Error handling - becomes less clear in this situation. When this is needed for code clarity, - it should be clearly documented. - - .. code:: python - - def myfunc(foo): - session = sessionmaker() - with session.begin(): - # do some database things - bar = _private_func(foo, session) - return bar - - def _private_func(foo, session=None): - if not session: - session = sessionmaker() - with session.begin(subtransaction=True): - # do some other database things - return bar - - -There are some things which it is best to avoid: - -* Don't keep a transaction open any longer than necessary. - - This means that your ``with session.begin()`` block should be as short - as possible, while still containing all the related calls for that - transaction. - -* Avoid ``with_lockmode('UPDATE')`` when possible. - - In MySQL/InnoDB, when a ``SELECT ... FOR UPDATE`` query does not match - any rows, it will take a gap-lock. This is a form of write-lock on the - "gap" where no rows exist, and prevents any other writes to that space. - This can effectively prevent any INSERT into a table by locking the gap - at the end of the index. Similar problems will occur if the SELECT FOR UPDATE - has an overly broad WHERE clause, or doesn't properly use an index. - - One idea proposed at ODS Fall '12 was to use a normal SELECT to test the - number of rows matching a query, and if only one row is returned, - then issue the SELECT FOR UPDATE. - - The better long-term solution is to use - ``INSERT .. ON DUPLICATE KEY UPDATE``. - However, this can not be done until the "deleted" columns are removed and - proper UNIQUE constraints are added to the tables. - - -Enabling soft deletes: - -* To use/enable soft-deletes, the `SoftDeleteMixin` must be added - to your model class. For example: - - .. code:: python - - class NovaBase(models.SoftDeleteMixin, models.ModelBase): - pass - - -Efficient use of soft deletes: - -* There are two possible ways to mark a record as deleted: - `model.soft_delete()` and `query.soft_delete()`. - - The `model.soft_delete()` method works with a single already-fetched entry. - `query.soft_delete()` makes only one db request for all entries that - correspond to the query. - -* In almost all cases you should use `query.soft_delete()`. Some examples: - - .. code:: python - - def soft_delete_bar(): - count = model_query(BarModel).find(some_condition).soft_delete() - if count == 0: - raise Exception("0 entries were soft deleted") - - def complex_soft_delete_with_synchronization_bar(session=None): - if session is None: - session = sessionmaker() - with session.begin(subtransactions=True): - count = (model_query(BarModel). - find(some_condition). - soft_delete(synchronize_session=True)) - # Here synchronize_session is required, because we - # don't know what is going on in outer session. - if count == 0: - raise Exception("0 entries were soft deleted") - -* There is only one situation where `model.soft_delete()` is appropriate: when - you fetch a single record, work with it, and mark it as deleted in the same - transaction. - - .. code:: python - - def soft_delete_bar_model(): - session = sessionmaker() - with session.begin(): - bar_ref = model_query(BarModel).find(some_condition).first() - # Work with bar_ref - bar_ref.soft_delete(session=session) - - However, if you need to work with all entries that correspond to query and - then soft delete them you should use the `query.soft_delete()` method: - - .. code:: python - - def soft_delete_multi_models(): - session = sessionmaker() - with session.begin(): - query = (model_query(BarModel, session=session). - find(some_condition)) - model_refs = query.all() - # Work with model_refs - query.soft_delete(synchronize_session=False) - # synchronize_session=False should be set if there is no outer - # session and these entries are not used after this. - - When working with many rows, it is very important to use query.soft_delete, - which issues a single query. Using `model.soft_delete()`, as in the following - example, is very inefficient. - - .. code:: python - - for bar_ref in bar_refs: - bar_ref.soft_delete(session=session) - # This will produce count(bar_refs) db requests. - -""" - -import functools -import logging -import re -import time - -import six -from sqlalchemy import exc as sqla_exc -from sqlalchemy.interfaces import PoolListener -import sqlalchemy.orm -from sqlalchemy.pool import NullPool, StaticPool -from sqlalchemy.sql.expression import literal_column - -from graffiti.openstack.common.db import exception -from graffiti.openstack.common.gettextutils import _LE, _LW, _LI -from graffiti.openstack.common import timeutils - - -LOG = logging.getLogger(__name__) - - -class SqliteForeignKeysListener(PoolListener): - """Ensures that the foreign key constraints are enforced in SQLite. - - The foreign key constraints are disabled by default in SQLite, - so the foreign key constraints will be enabled here for every - database connection - """ - def connect(self, dbapi_con, con_record): - dbapi_con.execute('pragma foreign_keys=ON') - - -# note(boris-42): In current versions of DB backends unique constraint -# violation messages follow the structure: -# -# sqlite: -# 1 column - (IntegrityError) column c1 is not unique -# N columns - (IntegrityError) column c1, c2, ..., N are not unique -# -# sqlite since 3.7.16: -# 1 column - (IntegrityError) UNIQUE constraint failed: tbl.k1 -# -# N columns - (IntegrityError) UNIQUE constraint failed: tbl.k1, tbl.k2 -# -# postgres: -# 1 column - (IntegrityError) duplicate key value violates unique -# constraint "users_c1_key" -# N columns - (IntegrityError) duplicate key value violates unique -# constraint "name_of_our_constraint" -# -# mysql: -# 1 column - (IntegrityError) (1062, "Duplicate entry 'value_of_c1' for key -# 'c1'") -# N columns - (IntegrityError) (1062, "Duplicate entry 'values joined -# with -' for key 'name_of_our_constraint'") -# -# ibm_db_sa: -# N columns - (IntegrityError) SQL0803N One or more values in the INSERT -# statement, UPDATE statement, or foreign key update caused by a -# DELETE statement are not valid because the primary key, unique -# constraint or unique index identified by "2" constrains table -# "NOVA.KEY_PAIRS" from having duplicate values for the index -# key. -_DUP_KEY_RE_DB = { - "sqlite": (re.compile(r"^.*columns?([^)]+)(is|are)\s+not\s+unique$"), - re.compile(r"^.*UNIQUE\s+constraint\s+failed:\s+(.+)$")), - "postgresql": (re.compile(r"^.*duplicate\s+key.*\"([^\"]+)\"\s*\n.*$"),), - "mysql": (re.compile(r"^.*\(1062,.*'([^\']+)'\"\)$"),), - "ibm_db_sa": (re.compile(r"^.*SQL0803N.*$"),), -} - - -def _raise_if_duplicate_entry_error(integrity_error, engine_name): - """Raise exception if two entries are duplicated. - - In this function will be raised DBDuplicateEntry exception if integrity - error wrap unique constraint violation. - """ - - def get_columns_from_uniq_cons_or_name(columns): - # note(vsergeyev): UniqueConstraint name convention: "uniq_t0c10c2" - # where `t` it is table name and columns `c1`, `c2` - # are in UniqueConstraint. - uniqbase = "uniq_" - if not columns.startswith(uniqbase): - if engine_name == "postgresql": - return [columns[columns.index("_") + 1:columns.rindex("_")]] - return [columns] - return columns[len(uniqbase):].split("0")[1:] - - if engine_name not in ["ibm_db_sa", "mysql", "sqlite", "postgresql"]: - return - - # FIXME(johannes): The usage of the .message attribute has been - # deprecated since Python 2.6. However, the exceptions raised by - # SQLAlchemy can differ when using unicode() and accessing .message. - # An audit across all three supported engines will be necessary to - # ensure there are no regressions. - for pattern in _DUP_KEY_RE_DB[engine_name]: - match = pattern.match(integrity_error.message) - if match: - break - else: - return - - # NOTE(mriedem): The ibm_db_sa integrity error message doesn't provide the - # columns so we have to omit that from the DBDuplicateEntry error. - columns = '' - - if engine_name != 'ibm_db_sa': - columns = match.group(1) - - if engine_name == "sqlite": - columns = [c.split('.')[-1] for c in columns.strip().split(", ")] - else: - columns = get_columns_from_uniq_cons_or_name(columns) - raise exception.DBDuplicateEntry(columns, integrity_error) - - -# NOTE(comstud): In current versions of DB backends, Deadlock violation -# messages follow the structure: -# -# mysql: -# (OperationalError) (1213, 'Deadlock found when trying to get lock; try ' -# 'restarting transaction') -_DEADLOCK_RE_DB = { - "mysql": re.compile(r"^.*\(1213, 'Deadlock.*") -} - - -def _raise_if_deadlock_error(operational_error, engine_name): - """Raise exception on deadlock condition. - - Raise DBDeadlock exception if OperationalError contains a Deadlock - condition. - """ - re = _DEADLOCK_RE_DB.get(engine_name) - if re is None: - return - # FIXME(johannes): The usage of the .message attribute has been - # deprecated since Python 2.6. However, the exceptions raised by - # SQLAlchemy can differ when using unicode() and accessing .message. - # An audit across all three supported engines will be necessary to - # ensure there are no regressions. - m = re.match(operational_error.message) - if not m: - return - raise exception.DBDeadlock(operational_error) - - -def _wrap_db_error(f): - #TODO(rpodolyaka): in a subsequent commit make this a class decorator to - # ensure it can only applied to Session subclasses instances (as we use - # Session instance bind attribute below) - - @functools.wraps(f) - def _wrap(self, *args, **kwargs): - try: - return f(self, *args, **kwargs) - except UnicodeEncodeError: - raise exception.DBInvalidUnicodeParameter() - except sqla_exc.OperationalError as e: - _raise_if_db_connection_lost(e, self.bind) - _raise_if_deadlock_error(e, self.bind.dialect.name) - # NOTE(comstud): A lot of code is checking for OperationalError - # so let's not wrap it for now. - raise - # note(boris-42): We should catch unique constraint violation and - # wrap it by our own DBDuplicateEntry exception. Unique constraint - # violation is wrapped by IntegrityError. - except sqla_exc.IntegrityError as e: - # note(boris-42): SqlAlchemy doesn't unify errors from different - # DBs so we must do this. Also in some tables (for example - # instance_types) there are more than one unique constraint. This - # means we should get names of columns, which values violate - # unique constraint, from error message. - _raise_if_duplicate_entry_error(e, self.bind.dialect.name) - raise exception.DBError(e) - except Exception as e: - LOG.exception(_LE('DB exception wrapped.')) - raise exception.DBError(e) - return _wrap - - -def _synchronous_switch_listener(dbapi_conn, connection_rec): - """Switch sqlite connections to non-synchronous mode.""" - dbapi_conn.execute("PRAGMA synchronous = OFF") - - -def _add_regexp_listener(dbapi_con, con_record): - """Add REGEXP function to sqlite connections.""" - - def regexp(expr, item): - reg = re.compile(expr) - return reg.search(six.text_type(item)) is not None - dbapi_con.create_function('regexp', 2, regexp) - - -def _thread_yield(dbapi_con, con_record): - """Ensure other greenthreads get a chance to be executed. - - If we use eventlet.monkey_patch(), eventlet.greenthread.sleep(0) will - execute instead of time.sleep(0). - Force a context switch. With common database backends (eg MySQLdb and - sqlite), there is no implicit yield caused by network I/O since they are - implemented by C libraries that eventlet cannot monkey patch. - """ - time.sleep(0) - - -def _ping_listener(engine, dbapi_conn, connection_rec, connection_proxy): - """Ensures that MySQL and DB2 connections are alive. - - Borrowed from: - http://groups.google.com/group/sqlalchemy/msg/a4ce563d802c929f - """ - cursor = dbapi_conn.cursor() - try: - ping_sql = 'select 1' - if engine.name == 'ibm_db_sa': - # DB2 requires a table expression - ping_sql = 'select 1 from (values (1)) AS t1' - cursor.execute(ping_sql) - except Exception as ex: - if engine.dialect.is_disconnect(ex, dbapi_conn, cursor): - msg = _LW('Database server has gone away: %s') % ex - LOG.warning(msg) - raise sqla_exc.DisconnectionError(msg) - else: - raise - - -def _set_mode_traditional(dbapi_con, connection_rec, connection_proxy): - """Set engine mode to 'traditional'. - - Required to prevent silent truncates at insert or update operations - under MySQL. By default MySQL truncates inserted string if it longer - than a declared field just with warning. That is fraught with data - corruption. - """ - _set_session_sql_mode(dbapi_con, connection_rec, - connection_proxy, 'TRADITIONAL') - - -def _set_session_sql_mode(dbapi_con, connection_rec, - connection_proxy, sql_mode=None): - """Set the sql_mode session variable. - - MySQL supports several server modes. The default is None, but sessions - may choose to enable server modes like TRADITIONAL, ANSI, - several STRICT_* modes and others. - - Note: passing in '' (empty string) for sql_mode clears - the SQL mode for the session, overriding a potentially set - server default. Passing in None (the default) makes this - a no-op, meaning if a server-side SQL mode is set, it still applies. - """ - cursor = dbapi_con.cursor() - if sql_mode is not None: - cursor.execute("SET SESSION sql_mode = %s", [sql_mode]) - - # Check against the real effective SQL mode. Even when unset by - # our own config, the server may still be operating in a specific - # SQL mode as set by the server configuration - cursor.execute("SHOW VARIABLES LIKE 'sql_mode'") - row = cursor.fetchone() - if row is None: - LOG.warning(_LW('Unable to detect effective SQL mode')) - return - realmode = row[1] - LOG.info(_LI('MySQL server mode set to %s') % realmode) - # 'TRADITIONAL' mode enables several other modes, so - # we need a substring match here - if not ('TRADITIONAL' in realmode.upper() or - 'STRICT_ALL_TABLES' in realmode.upper()): - LOG.warning(_LW("MySQL SQL mode is '%s', " - "consider enabling TRADITIONAL or STRICT_ALL_TABLES") - % realmode) - - -def _is_db_connection_error(args): - """Return True if error in connecting to db.""" - # NOTE(adam_g): This is currently MySQL specific and needs to be extended - # to support Postgres and others. - # For the db2, the error code is -30081 since the db2 is still not ready - conn_err_codes = ('2002', '2003', '2006', '2013', '-30081') - for err_code in conn_err_codes: - if args.find(err_code) != -1: - return True - return False - - -def _raise_if_db_connection_lost(error, engine): - # NOTE(vsergeyev): Function is_disconnect(e, connection, cursor) - # requires connection and cursor in incoming parameters, - # but we have no possibility to create connection if DB - # is not available, so in such case reconnect fails. - # But is_disconnect() ignores these parameters, so it - # makes sense to pass to function None as placeholder - # instead of connection and cursor. - if engine.dialect.is_disconnect(error, None, None): - raise exception.DBConnectionError(error) - - -def create_engine(sql_connection, sqlite_fk=False, mysql_sql_mode=None, - mysql_traditional_mode=False, idle_timeout=3600, - connection_debug=0, max_pool_size=None, max_overflow=None, - pool_timeout=None, sqlite_synchronous=True, - connection_trace=False, max_retries=10, retry_interval=10): - """Return a new SQLAlchemy engine.""" - - connection_dict = sqlalchemy.engine.url.make_url(sql_connection) - - engine_args = { - "pool_recycle": idle_timeout, - 'convert_unicode': True, - } - - logger = logging.getLogger('sqlalchemy.engine') - - # Map SQL debug level to Python log level - if connection_debug >= 100: - logger.setLevel(logging.DEBUG) - elif connection_debug >= 50: - logger.setLevel(logging.INFO) - else: - logger.setLevel(logging.WARNING) - - if "sqlite" in connection_dict.drivername: - if sqlite_fk: - engine_args["listeners"] = [SqliteForeignKeysListener()] - engine_args["poolclass"] = NullPool - - if sql_connection == "sqlite://": - engine_args["poolclass"] = StaticPool - engine_args["connect_args"] = {'check_same_thread': False} - else: - if max_pool_size is not None: - engine_args['pool_size'] = max_pool_size - if max_overflow is not None: - engine_args['max_overflow'] = max_overflow - if pool_timeout is not None: - engine_args['pool_timeout'] = pool_timeout - - engine = sqlalchemy.create_engine(sql_connection, **engine_args) - - sqlalchemy.event.listen(engine, 'checkin', _thread_yield) - - if engine.name in ['mysql', 'ibm_db_sa']: - ping_callback = functools.partial(_ping_listener, engine) - sqlalchemy.event.listen(engine, 'checkout', ping_callback) - if engine.name == 'mysql': - if mysql_traditional_mode: - mysql_sql_mode = 'TRADITIONAL' - if mysql_sql_mode: - mode_callback = functools.partial(_set_session_sql_mode, - sql_mode=mysql_sql_mode) - sqlalchemy.event.listen(engine, 'checkout', mode_callback) - elif 'sqlite' in connection_dict.drivername: - if not sqlite_synchronous: - sqlalchemy.event.listen(engine, 'connect', - _synchronous_switch_listener) - sqlalchemy.event.listen(engine, 'connect', _add_regexp_listener) - - if connection_trace and engine.dialect.dbapi.__name__ == 'MySQLdb': - _patch_mysqldb_with_stacktrace_comments() - - try: - engine.connect() - except sqla_exc.OperationalError as e: - if not _is_db_connection_error(e.args[0]): - raise - - remaining = max_retries - if remaining == -1: - remaining = 'infinite' - while True: - msg = _LW('SQL connection failed. %s attempts left.') - LOG.warning(msg % remaining) - if remaining != 'infinite': - remaining -= 1 - time.sleep(retry_interval) - try: - engine.connect() - break - except sqla_exc.OperationalError as e: - if (remaining != 'infinite' and remaining == 0) or \ - not _is_db_connection_error(e.args[0]): - raise - return engine - - -class Query(sqlalchemy.orm.query.Query): - """Subclass of sqlalchemy.query with soft_delete() method.""" - def soft_delete(self, synchronize_session='evaluate'): - return self.update({'deleted': literal_column('id'), - 'updated_at': literal_column('updated_at'), - 'deleted_at': timeutils.utcnow()}, - synchronize_session=synchronize_session) - - -class Session(sqlalchemy.orm.session.Session): - """Custom Session class to avoid SqlAlchemy Session monkey patching.""" - @_wrap_db_error - def query(self, *args, **kwargs): - return super(Session, self).query(*args, **kwargs) - - @_wrap_db_error - def flush(self, *args, **kwargs): - return super(Session, self).flush(*args, **kwargs) - - @_wrap_db_error - def execute(self, *args, **kwargs): - return super(Session, self).execute(*args, **kwargs) - - -def get_maker(engine, autocommit=True, expire_on_commit=False): - """Return a SQLAlchemy sessionmaker using the given engine.""" - return sqlalchemy.orm.sessionmaker(bind=engine, - class_=Session, - autocommit=autocommit, - expire_on_commit=expire_on_commit, - query_cls=Query) - - -def _patch_mysqldb_with_stacktrace_comments(): - """Adds current stack trace as a comment in queries. - - Patches MySQLdb.cursors.BaseCursor._do_query. - """ - import MySQLdb.cursors - import traceback - - old_mysql_do_query = MySQLdb.cursors.BaseCursor._do_query - - def _do_query(self, q): - stack = '' - for filename, line, method, function in traceback.extract_stack(): - # exclude various common things from trace - if filename.endswith('session.py') and method == '_do_query': - continue - if filename.endswith('api.py') and method == 'wrapper': - continue - if filename.endswith('utils.py') and method == '_inner': - continue - if filename.endswith('exception.py') and method == '_wrap': - continue - # db/api is just a wrapper around db/sqlalchemy/api - if filename.endswith('db/api.py'): - continue - # only trace inside graffiti - index = filename.rfind('graffiti') - if index == -1: - continue - stack += "File:%s:%s Method:%s() Line:%s | " \ - % (filename[index:], line, method, function) - - # strip trailing " | " from stack - if stack: - stack = stack[:-3] - qq = "%s /* %s */" % (q, stack) - else: - qq = q - old_mysql_do_query(self, qq) - - setattr(MySQLdb.cursors.BaseCursor, '_do_query', _do_query) - - -class EngineFacade(object): - """A helper class for removing of global engine instances from graffiti.db. - - As a library, graffiti.db can't decide where to store/when to create engine - and sessionmaker instances, so this must be left for a target application. - - On the other hand, in order to simplify the adoption of graffiti.db change - we'll provide a helper class, which creates engine and sessionmaker - on its instantiation and provides get_engine()/get_session() methods - that are compatible with corresponding utility functions that currently - exist in target projects, e.g. in Nova. - - engine/sessionmaker instances will still be global (and they are meant to - be global), but they will be stored in the app context, rather that in the - graffiti.db context. - - Note: using of this helper is completely optional and you are encouraged to - integrate engine/sessionmaker instances into your apps any way you like - (e.g. one might want to bind a session to a request context). Two important - things to remember: - 1. An Engine instance is effectively a pool of DB connections, so it's - meant to be shared (and it's thread-safe). - 2. A Session instance is not meant to be shared and represents a DB - transactional context (i.e. it's not thread-safe). sessionmaker is - a factory of sessions. - - """ - - def __init__(self, sql_connection, - sqlite_fk=False, mysql_sql_mode=None, - autocommit=True, expire_on_commit=False, **kwargs): - """Initialize engine and sessionmaker instances. - - :param sqlite_fk: enable foreign keys in SQLite - :type sqlite_fk: bool - - :param mysql_sql_mode: set SQL mode in MySQL - :type mysql_sql_mode: string - - :param autocommit: use autocommit mode for created Session instances - :type autocommit: bool - - :param expire_on_commit: expire session objects on commit - :type expire_on_commit: bool - - Keyword arguments: - - :keyword idle_timeout: timeout before idle sql connections are reaped - (defaults to 3600) - :keyword connection_debug: verbosity of SQL debugging information. - 0=None, 100=Everything (defaults to 0) - :keyword max_pool_size: maximum number of SQL connections to keep open - in a pool (defaults to SQLAlchemy settings) - :keyword max_overflow: if set, use this value for max_overflow with - sqlalchemy (defaults to SQLAlchemy settings) - :keyword pool_timeout: if set, use this value for pool_timeout with - sqlalchemy (defaults to SQLAlchemy settings) - :keyword sqlite_synchronous: if True, SQLite uses synchronous mode - (defaults to True) - :keyword connection_trace: add python stack traces to SQL as comment - strings (defaults to False) - :keyword max_retries: maximum db connection retries during startup. - (setting -1 implies an infinite retry count) - (defaults to 10) - :keyword retry_interval: interval between retries of opening a sql - connection (defaults to 10) - - """ - - super(EngineFacade, self).__init__() - self._engine = create_engine( - sql_connection=sql_connection, - sqlite_fk=sqlite_fk, - mysql_sql_mode=mysql_sql_mode, - idle_timeout=kwargs.get('idle_timeout', 3600), - connection_debug=kwargs.get('connection_debug', 0), - max_pool_size=kwargs.get('max_pool_size'), - max_overflow=kwargs.get('max_overflow'), - pool_timeout=kwargs.get('pool_timeout'), - sqlite_synchronous=kwargs.get('sqlite_synchronous', True), - connection_trace=kwargs.get('connection_trace', False), - max_retries=kwargs.get('max_retries', 10), - retry_interval=kwargs.get('retry_interval', 10)) - self._session_maker = get_maker( - engine=self._engine, - autocommit=autocommit, - expire_on_commit=expire_on_commit) - - def get_engine(self): - """Get the engine instance (note, that it's shared).""" - - return self._engine - - def get_session(self, **kwargs): - """Get a Session instance. - - If passed, keyword arguments values override the ones used when the - sessionmaker instance was created. - - :keyword autocommit: use autocommit mode for created Session instances - :type autocommit: bool - - :keyword expire_on_commit: expire session objects on commit - :type expire_on_commit: bool - - """ - - for arg in kwargs: - if arg not in ('autocommit', 'expire_on_commit'): - del kwargs[arg] - - return self._session_maker(**kwargs) - - @classmethod - def from_config(cls, connection_string, conf, - sqlite_fk=False, mysql_sql_mode=None, - autocommit=True, expire_on_commit=False): - """Initialize EngineFacade using oslo.config config instance options. - - :param connection_string: SQLAlchemy connection string - :type connection_string: string - - :param conf: oslo.config config instance - :type conf: oslo.config.cfg.ConfigOpts - - :param sqlite_fk: enable foreign keys in SQLite - :type sqlite_fk: bool - - :param mysql_sql_mode: set SQL mode in MySQL - :type mysql_sql_mode: string - - :param autocommit: use autocommit mode for created Session instances - :type autocommit: bool - - :param expire_on_commit: expire session objects on commit - :type expire_on_commit: bool - - """ - - return cls(sql_connection=connection_string, - sqlite_fk=sqlite_fk, - mysql_sql_mode=mysql_sql_mode, - autocommit=autocommit, - expire_on_commit=expire_on_commit, - **dict(conf.database.items())) diff --git a/graffiti/openstack/common/db/sqlalchemy/utils.py b/graffiti/openstack/common/db/sqlalchemy/utils.py deleted file mode 100644 index a88b08f..0000000 --- a/graffiti/openstack/common/db/sqlalchemy/utils.py +++ /dev/null @@ -1,638 +0,0 @@ -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# Copyright 2010-2011 OpenStack Foundation. -# Copyright 2012 Justin Santa Barbara -# All Rights Reserved. -# -# 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. - -import logging -import re - -from migrate.changeset import UniqueConstraint -import sqlalchemy -from sqlalchemy import Boolean -from sqlalchemy import CheckConstraint -from sqlalchemy import Column -from sqlalchemy.engine import reflection -from sqlalchemy.ext.compiler import compiles -from sqlalchemy import func -from sqlalchemy import Index -from sqlalchemy import Integer -from sqlalchemy import MetaData -from sqlalchemy import or_ -from sqlalchemy.sql.expression import literal_column -from sqlalchemy.sql.expression import UpdateBase -from sqlalchemy.sql import select -from sqlalchemy import String -from sqlalchemy import Table -from sqlalchemy.types import NullType - -from graffiti.openstack.common import context as request_context -from graffiti.openstack.common.db.sqlalchemy import models -from graffiti.openstack.common.gettextutils import _, _LI, _LW -from graffiti.openstack.common import timeutils - - -LOG = logging.getLogger(__name__) - -_DBURL_REGEX = re.compile(r"[^:]+://([^:]+):([^@]+)@.+") - - -def sanitize_db_url(url): - match = _DBURL_REGEX.match(url) - if match: - return '%s****:****%s' % (url[:match.start(1)], url[match.end(2):]) - return url - - -class InvalidSortKey(Exception): - message = _("Sort key supplied was not valid.") - - -# copy from glance/db/sqlalchemy/api.py -def paginate_query(query, model, limit, sort_keys, marker=None, - sort_dir=None, sort_dirs=None): - """Returns a query with sorting / pagination criteria added. - - Pagination works by requiring a unique sort_key, specified by sort_keys. - (If sort_keys is not unique, then we risk looping through values.) - We use the last row in the previous page as the 'marker' for pagination. - So we must return values that follow the passed marker in the order. - With a single-valued sort_key, this would be easy: sort_key > X. - With a compound-values sort_key, (k1, k2, k3) we must do this to repeat - the lexicographical ordering: - (k1 > X1) or (k1 == X1 && k2 > X2) or (k1 == X1 && k2 == X2 && k3 > X3) - - We also have to cope with different sort_directions. - - Typically, the id of the last row is used as the client-facing pagination - marker, then the actual marker object must be fetched from the db and - passed in to us as marker. - - :param query: the query object to which we should add paging/sorting - :param model: the ORM model class - :param limit: maximum number of items to return - :param sort_keys: array of attributes by which results should be sorted - :param marker: the last item of the previous page; we returns the next - results after this value. - :param sort_dir: direction in which results should be sorted (asc, desc) - :param sort_dirs: per-column array of sort_dirs, corresponding to sort_keys - - :rtype: sqlalchemy.orm.query.Query - :return: The query with sorting/pagination added. - """ - - if 'id' not in sort_keys: - # TODO(justinsb): If this ever gives a false-positive, check - # the actual primary key, rather than assuming its id - LOG.warning(_LW('Id not in sort_keys; is sort_keys unique?')) - - assert(not (sort_dir and sort_dirs)) - - # Default the sort direction to ascending - if sort_dirs is None and sort_dir is None: - sort_dir = 'asc' - - # Ensure a per-column sort direction - if sort_dirs is None: - sort_dirs = [sort_dir for _sort_key in sort_keys] - - assert(len(sort_dirs) == len(sort_keys)) - - # Add sorting - for current_sort_key, current_sort_dir in zip(sort_keys, sort_dirs): - try: - sort_dir_func = { - 'asc': sqlalchemy.asc, - 'desc': sqlalchemy.desc, - }[current_sort_dir] - except KeyError: - raise ValueError(_("Unknown sort direction, " - "must be 'desc' or 'asc'")) - try: - sort_key_attr = getattr(model, current_sort_key) - except AttributeError: - raise InvalidSortKey() - query = query.order_by(sort_dir_func(sort_key_attr)) - - # Add pagination - if marker is not None: - marker_values = [] - for sort_key in sort_keys: - v = getattr(marker, sort_key) - marker_values.append(v) - - # Build up an array of sort criteria as in the docstring - criteria_list = [] - for i in range(len(sort_keys)): - crit_attrs = [] - for j in range(i): - model_attr = getattr(model, sort_keys[j]) - crit_attrs.append((model_attr == marker_values[j])) - - model_attr = getattr(model, sort_keys[i]) - if sort_dirs[i] == 'desc': - crit_attrs.append((model_attr < marker_values[i])) - else: - crit_attrs.append((model_attr > marker_values[i])) - - criteria = sqlalchemy.sql.and_(*crit_attrs) - criteria_list.append(criteria) - - f = sqlalchemy.sql.or_(*criteria_list) - query = query.filter(f) - - if limit is not None: - query = query.limit(limit) - - return query - - -def _read_deleted_filter(query, db_model, read_deleted): - if 'deleted' not in db_model.__table__.columns: - raise ValueError(_("There is no `deleted` column in `%s` table. " - "Project doesn't use soft-deleted feature.") - % db_model.__name__) - - default_deleted_value = db_model.__table__.c.deleted.default.arg - if read_deleted == 'no': - query = query.filter(db_model.deleted == default_deleted_value) - elif read_deleted == 'yes': - pass # omit the filter to include deleted and active - elif read_deleted == 'only': - query = query.filter(db_model.deleted != default_deleted_value) - else: - raise ValueError(_("Unrecognized read_deleted value '%s'") - % read_deleted) - return query - - -def _project_filter(query, db_model, context, project_only): - if project_only and 'project_id' not in db_model.__table__.columns: - raise ValueError(_("There is no `project_id` column in `%s` table.") - % db_model.__name__) - - if request_context.is_user_context(context) and project_only: - if project_only == 'allow_none': - is_none = None - query = query.filter(or_(db_model.project_id == context.project_id, - db_model.project_id == is_none)) - else: - query = query.filter(db_model.project_id == context.project_id) - - return query - - -def model_query(context, model, session, args=None, project_only=False, - read_deleted=None): - """Query helper that accounts for context's `read_deleted` field. - - :param context: context to query under - - :param model: Model to query. Must be a subclass of ModelBase. - :type model: models.ModelBase - - :param session: The session to use. - :type session: sqlalchemy.orm.session.Session - - :param args: Arguments to query. If None - model is used. - :type args: tuple - - :param project_only: If present and context is user-type, then restrict - query to match the context's project_id. If set to - 'allow_none', restriction includes project_id = None. - :type project_only: bool - - :param read_deleted: If present, overrides context's read_deleted field. - :type read_deleted: bool - - Usage: - result = (utils.model_query(context, models.Instance, session=session) - .filter_by(uuid=instance_uuid) - .all()) - - query = utils.model_query( - context, Node, - session=session, - args=(func.count(Node.id), func.sum(Node.ram)) - ).filter_by(project_id=project_id) - """ - - if not read_deleted: - if hasattr(context, 'read_deleted'): - # NOTE(viktors): some projects use `read_deleted` attribute in - # their contexts instead of `show_deleted`. - read_deleted = context.read_deleted - else: - read_deleted = context.show_deleted - - if not issubclass(model, models.ModelBase): - raise TypeError(_("model should be a subclass of ModelBase")) - - query = session.query(model) if not args else session.query(*args) - query = _read_deleted_filter(query, model, read_deleted) - query = _project_filter(query, model, context, project_only) - - return query - - -def get_table(engine, name): - """Returns an sqlalchemy table dynamically from db. - - Needed because the models don't work for us in migrations - as models will be far out of sync with the current data. - """ - metadata = MetaData() - metadata.bind = engine - return Table(name, metadata, autoload=True) - - -class InsertFromSelect(UpdateBase): - """Form the base for `INSERT INTO table (SELECT ... )` statement.""" - def __init__(self, table, select): - self.table = table - self.select = select - - -@compiles(InsertFromSelect) -def visit_insert_from_select(element, compiler, **kw): - """Form the `INSERT INTO table (SELECT ... )` statement.""" - return "INSERT INTO %s %s" % ( - compiler.process(element.table, asfrom=True), - compiler.process(element.select)) - - -class ColumnError(Exception): - """Error raised when no column or an invalid column is found.""" - - -def _get_not_supported_column(col_name_col_instance, column_name): - try: - column = col_name_col_instance[column_name] - except KeyError: - msg = _("Please specify column %s in col_name_col_instance " - "param. It is required because column has unsupported " - "type by sqlite).") - raise ColumnError(msg % column_name) - - if not isinstance(column, Column): - msg = _("col_name_col_instance param has wrong type of " - "column instance for column %s It should be instance " - "of sqlalchemy.Column.") - raise ColumnError(msg % column_name) - return column - - -def drop_unique_constraint(migrate_engine, table_name, uc_name, *columns, - **col_name_col_instance): - """Drop unique constraint from table. - - This method drops UC from table and works for mysql, postgresql and sqlite. - In mysql and postgresql we are able to use "alter table" construction. - Sqlalchemy doesn't support some sqlite column types and replaces their - type with NullType in metadata. We process these columns and replace - NullType with the correct column type. - - :param migrate_engine: sqlalchemy engine - :param table_name: name of table that contains uniq constraint. - :param uc_name: name of uniq constraint that will be dropped. - :param columns: columns that are in uniq constraint. - :param col_name_col_instance: contains pair column_name=column_instance. - column_instance is instance of Column. These params - are required only for columns that have unsupported - types by sqlite. For example BigInteger. - """ - - meta = MetaData() - meta.bind = migrate_engine - t = Table(table_name, meta, autoload=True) - - if migrate_engine.name == "sqlite": - override_cols = [ - _get_not_supported_column(col_name_col_instance, col.name) - for col in t.columns - if isinstance(col.type, NullType) - ] - for col in override_cols: - t.columns.replace(col) - - uc = UniqueConstraint(*columns, table=t, name=uc_name) - uc.drop() - - -def drop_old_duplicate_entries_from_table(migrate_engine, table_name, - use_soft_delete, *uc_column_names): - """Drop all old rows having the same values for columns in uc_columns. - - This method drop (or mark ad `deleted` if use_soft_delete is True) old - duplicate rows form table with name `table_name`. - - :param migrate_engine: Sqlalchemy engine - :param table_name: Table with duplicates - :param use_soft_delete: If True - values will be marked as `deleted`, - if False - values will be removed from table - :param uc_column_names: Unique constraint columns - """ - meta = MetaData() - meta.bind = migrate_engine - - table = Table(table_name, meta, autoload=True) - columns_for_group_by = [table.c[name] for name in uc_column_names] - - columns_for_select = [func.max(table.c.id)] - columns_for_select.extend(columns_for_group_by) - - duplicated_rows_select = select(columns_for_select, - group_by=columns_for_group_by, - having=func.count(table.c.id) > 1) - - for row in migrate_engine.execute(duplicated_rows_select): - # NOTE(boris-42): Do not remove row that has the biggest ID. - delete_condition = table.c.id != row[0] - is_none = None # workaround for pyflakes - delete_condition &= table.c.deleted_at == is_none - for name in uc_column_names: - delete_condition &= table.c[name] == row[name] - - rows_to_delete_select = select([table.c.id]).where(delete_condition) - for row in migrate_engine.execute(rows_to_delete_select).fetchall(): - LOG.info(_LI("Deleting duplicated row with id: %(id)s from table: " - "%(table)s") % dict(id=row[0], table=table_name)) - - if use_soft_delete: - delete_statement = table.update().\ - where(delete_condition).\ - values({ - 'deleted': literal_column('id'), - 'updated_at': literal_column('updated_at'), - 'deleted_at': timeutils.utcnow() - }) - else: - delete_statement = table.delete().where(delete_condition) - migrate_engine.execute(delete_statement) - - -def _get_default_deleted_value(table): - if isinstance(table.c.id.type, Integer): - return 0 - if isinstance(table.c.id.type, String): - return "" - raise ColumnError(_("Unsupported id columns type")) - - -def _restore_indexes_on_deleted_columns(migrate_engine, table_name, indexes): - table = get_table(migrate_engine, table_name) - - insp = reflection.Inspector.from_engine(migrate_engine) - real_indexes = insp.get_indexes(table_name) - existing_index_names = dict( - [(index['name'], index['column_names']) for index in real_indexes]) - - # NOTE(boris-42): Restore indexes on `deleted` column - for index in indexes: - if 'deleted' not in index['column_names']: - continue - name = index['name'] - if name in existing_index_names: - column_names = [table.c[c] for c in existing_index_names[name]] - old_index = Index(name, *column_names, unique=index["unique"]) - old_index.drop(migrate_engine) - - column_names = [table.c[c] for c in index['column_names']] - new_index = Index(index["name"], *column_names, unique=index["unique"]) - new_index.create(migrate_engine) - - -def change_deleted_column_type_to_boolean(migrate_engine, table_name, - **col_name_col_instance): - if migrate_engine.name == "sqlite": - return _change_deleted_column_type_to_boolean_sqlite( - migrate_engine, table_name, **col_name_col_instance) - insp = reflection.Inspector.from_engine(migrate_engine) - indexes = insp.get_indexes(table_name) - - table = get_table(migrate_engine, table_name) - - old_deleted = Column('old_deleted', Boolean, default=False) - old_deleted.create(table, populate_default=False) - - table.update().\ - where(table.c.deleted == table.c.id).\ - values(old_deleted=True).\ - execute() - - table.c.deleted.drop() - table.c.old_deleted.alter(name="deleted") - - _restore_indexes_on_deleted_columns(migrate_engine, table_name, indexes) - - -def _change_deleted_column_type_to_boolean_sqlite(migrate_engine, table_name, - **col_name_col_instance): - insp = reflection.Inspector.from_engine(migrate_engine) - table = get_table(migrate_engine, table_name) - - columns = [] - for column in table.columns: - column_copy = None - if column.name != "deleted": - if isinstance(column.type, NullType): - column_copy = _get_not_supported_column(col_name_col_instance, - column.name) - else: - column_copy = column.copy() - else: - column_copy = Column('deleted', Boolean, default=0) - columns.append(column_copy) - - constraints = [constraint.copy() for constraint in table.constraints] - - meta = table.metadata - new_table = Table(table_name + "__tmp__", meta, - *(columns + constraints)) - new_table.create() - - indexes = [] - for index in insp.get_indexes(table_name): - column_names = [new_table.c[c] for c in index['column_names']] - indexes.append(Index(index["name"], *column_names, - unique=index["unique"])) - - c_select = [] - for c in table.c: - if c.name != "deleted": - c_select.append(c) - else: - c_select.append(table.c.deleted == table.c.id) - - ins = InsertFromSelect(new_table, select(c_select)) - migrate_engine.execute(ins) - - table.drop() - [index.create(migrate_engine) for index in indexes] - - new_table.rename(table_name) - new_table.update().\ - where(new_table.c.deleted == new_table.c.id).\ - values(deleted=True).\ - execute() - - -def change_deleted_column_type_to_id_type(migrate_engine, table_name, - **col_name_col_instance): - if migrate_engine.name == "sqlite": - return _change_deleted_column_type_to_id_type_sqlite( - migrate_engine, table_name, **col_name_col_instance) - insp = reflection.Inspector.from_engine(migrate_engine) - indexes = insp.get_indexes(table_name) - - table = get_table(migrate_engine, table_name) - - new_deleted = Column('new_deleted', table.c.id.type, - default=_get_default_deleted_value(table)) - new_deleted.create(table, populate_default=True) - - deleted = True # workaround for pyflakes - table.update().\ - where(table.c.deleted == deleted).\ - values(new_deleted=table.c.id).\ - execute() - table.c.deleted.drop() - table.c.new_deleted.alter(name="deleted") - - _restore_indexes_on_deleted_columns(migrate_engine, table_name, indexes) - - -def _change_deleted_column_type_to_id_type_sqlite(migrate_engine, table_name, - **col_name_col_instance): - # NOTE(boris-42): sqlaclhemy-migrate can't drop column with check - # constraints in sqlite DB and our `deleted` column has - # 2 check constraints. So there is only one way to remove - # these constraints: - # 1) Create new table with the same columns, constraints - # and indexes. (except deleted column). - # 2) Copy all data from old to new table. - # 3) Drop old table. - # 4) Rename new table to old table name. - insp = reflection.Inspector.from_engine(migrate_engine) - meta = MetaData(bind=migrate_engine) - table = Table(table_name, meta, autoload=True) - default_deleted_value = _get_default_deleted_value(table) - - columns = [] - for column in table.columns: - column_copy = None - if column.name != "deleted": - if isinstance(column.type, NullType): - column_copy = _get_not_supported_column(col_name_col_instance, - column.name) - else: - column_copy = column.copy() - else: - column_copy = Column('deleted', table.c.id.type, - default=default_deleted_value) - columns.append(column_copy) - - def is_deleted_column_constraint(constraint): - # NOTE(boris-42): There is no other way to check is CheckConstraint - # associated with deleted column. - if not isinstance(constraint, CheckConstraint): - return False - sqltext = str(constraint.sqltext) - return (sqltext.endswith("deleted in (0, 1)") or - sqltext.endswith("deleted IN (:deleted_1, :deleted_2)")) - - constraints = [] - for constraint in table.constraints: - if not is_deleted_column_constraint(constraint): - constraints.append(constraint.copy()) - - new_table = Table(table_name + "__tmp__", meta, - *(columns + constraints)) - new_table.create() - - indexes = [] - for index in insp.get_indexes(table_name): - column_names = [new_table.c[c] for c in index['column_names']] - indexes.append(Index(index["name"], *column_names, - unique=index["unique"])) - - ins = InsertFromSelect(new_table, table.select()) - migrate_engine.execute(ins) - - table.drop() - [index.create(migrate_engine) for index in indexes] - - new_table.rename(table_name) - deleted = True # workaround for pyflakes - new_table.update().\ - where(new_table.c.deleted == deleted).\ - values(deleted=new_table.c.id).\ - execute() - - # NOTE(boris-42): Fix value of deleted column: False -> "" or 0. - deleted = False # workaround for pyflakes - new_table.update().\ - where(new_table.c.deleted == deleted).\ - values(deleted=default_deleted_value).\ - execute() - - -def get_connect_string(backend, database, user=None, passwd=None): - """Get database connection - - Try to get a connection with a very specific set of values, if we get - these then we'll run the tests, otherwise they are skipped - """ - args = {'backend': backend, - 'user': user, - 'passwd': passwd, - 'database': database} - if backend == 'sqlite': - template = '%(backend)s:///%(database)s' - else: - template = "%(backend)s://%(user)s:%(passwd)s@localhost/%(database)s" - return template % args - - -def is_backend_avail(backend, database, user=None, passwd=None): - try: - connect_uri = get_connect_string(backend=backend, - database=database, - user=user, - passwd=passwd) - engine = sqlalchemy.create_engine(connect_uri) - connection = engine.connect() - except Exception: - # intentionally catch all to handle exceptions even if we don't - # have any backend code loaded. - return False - else: - connection.close() - engine.dispose() - return True - - -def get_db_connection_info(conn_pieces): - database = conn_pieces.path.strip('/') - loc_pieces = conn_pieces.netloc.split('@') - host = loc_pieces[1] - - auth_pieces = loc_pieces[0].split(':') - user = auth_pieces[0] - password = "" - if len(auth_pieces) > 1: - password = auth_pieces[1].strip() - - return (user, password, database, host) diff --git a/graffiti/openstack/common/excutils.py b/graffiti/openstack/common/excutils.py deleted file mode 100644 index 0739d2e..0000000 --- a/graffiti/openstack/common/excutils.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# Copyright 2012, Red Hat, Inc. -# -# 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. - -""" -Exception related utilities. -""" - -import logging -import sys -import time -import traceback - -import six - -from graffiti.openstack.common.gettextutils import _LE - - -class save_and_reraise_exception(object): - """Save current exception, run some code and then re-raise. - - In some cases the exception context can be cleared, resulting in None - being attempted to be re-raised after an exception handler is run. This - can happen when eventlet switches greenthreads or when running an - exception handler, code raises and catches an exception. In both - cases the exception context will be cleared. - - To work around this, we save the exception state, run handler code, and - then re-raise the original exception. If another exception occurs, the - saved exception is logged and the new exception is re-raised. - - In some cases the caller may not want to re-raise the exception, and - for those circumstances this context provides a reraise flag that - can be used to suppress the exception. For example:: - - except Exception: - with save_and_reraise_exception() as ctxt: - decide_if_need_reraise() - if not should_be_reraised: - ctxt.reraise = False - """ - def __init__(self): - self.reraise = True - - def __enter__(self): - self.type_, self.value, self.tb, = sys.exc_info() - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - if exc_type is not None: - logging.error(_LE('Original exception being dropped: %s'), - traceback.format_exception(self.type_, - self.value, - self.tb)) - return False - if self.reraise: - six.reraise(self.type_, self.value, self.tb) - - -def forever_retry_uncaught_exceptions(infunc): - def inner_func(*args, **kwargs): - last_log_time = 0 - last_exc_message = None - exc_count = 0 - while True: - try: - return infunc(*args, **kwargs) - except Exception as exc: - this_exc_message = six.u(str(exc)) - if this_exc_message == last_exc_message: - exc_count += 1 - else: - exc_count = 1 - # Do not log any more frequently than once a minute unless - # the exception message changes - cur_time = int(time.time()) - if (cur_time - last_log_time > 60 or - this_exc_message != last_exc_message): - logging.exception( - _LE('Unexpected exception occurred %d time(s)... ' - 'retrying.') % exc_count) - last_log_time = cur_time - last_exc_message = this_exc_message - exc_count = 0 - # This should be a very rare event. In case it isn't, do - # a sleep. - time.sleep(1) - return inner_func diff --git a/graffiti/openstack/common/fileutils.py b/graffiti/openstack/common/fileutils.py deleted file mode 100644 index e6957a9..0000000 --- a/graffiti/openstack/common/fileutils.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# 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. - -import contextlib -import errno -import os -import tempfile - -from graffiti.openstack.common import excutils -from graffiti.openstack.common import log as logging - -LOG = logging.getLogger(__name__) - -_FILE_CACHE = {} - - -def ensure_tree(path): - """Create a directory (and any ancestor directories required) - - :param path: Directory to create - """ - try: - os.makedirs(path) - except OSError as exc: - if exc.errno == errno.EEXIST: - if not os.path.isdir(path): - raise - else: - raise - - -def read_cached_file(filename, force_reload=False): - """Read from a file if it has been modified. - - :param force_reload: Whether to reload the file. - :returns: A tuple with a boolean specifying if the data is fresh - or not. - """ - global _FILE_CACHE - - if force_reload and filename in _FILE_CACHE: - del _FILE_CACHE[filename] - - reloaded = False - mtime = os.path.getmtime(filename) - cache_info = _FILE_CACHE.setdefault(filename, {}) - - if not cache_info or mtime > cache_info.get('mtime', 0): - LOG.debug("Reloading cached file %s" % filename) - with open(filename) as fap: - cache_info['data'] = fap.read() - cache_info['mtime'] = mtime - reloaded = True - return (reloaded, cache_info['data']) - - -def delete_if_exists(path, remove=os.unlink): - """Delete a file, but ignore file not found error. - - :param path: File to delete - :param remove: Optional function to remove passed path - """ - - try: - remove(path) - except OSError as e: - if e.errno != errno.ENOENT: - raise - - -@contextlib.contextmanager -def remove_path_on_error(path, remove=delete_if_exists): - """Protect code that wants to operate on PATH atomically. - Any exception will cause PATH to be removed. - - :param path: File to work with - :param remove: Optional function to remove passed path - """ - - try: - yield - except Exception: - with excutils.save_and_reraise_exception(): - remove(path) - - -def file_open(*args, **kwargs): - """Open file - - see built-in file() documentation for more details - - Note: The reason this is kept in a separate module is to easily - be able to provide a stub module that doesn't alter system - state at all (for unit tests) - """ - return file(*args, **kwargs) - - -def write_to_tempfile(content, path=None, suffix='', prefix='tmp'): - """Create temporary file or use existing file. - - This util is needed for creating temporary file with - specified content, suffix and prefix. If path is not None, - it will be used for writing content. If the path doesn't - exist it'll be created. - - :param content: content for temporary file. - :param path: same as parameter 'dir' for mkstemp - :param suffix: same as parameter 'suffix' for mkstemp - :param prefix: same as parameter 'prefix' for mkstemp - - For example: it can be used in database tests for creating - configuration files. - """ - if path: - ensure_tree(path) - - (fd, path) = tempfile.mkstemp(suffix=suffix, dir=path, prefix=prefix) - try: - os.write(fd, content) - finally: - os.close(fd) - return path diff --git a/graffiti/openstack/common/gettextutils.py b/graffiti/openstack/common/gettextutils.py deleted file mode 100644 index 4da8e2e..0000000 --- a/graffiti/openstack/common/gettextutils.py +++ /dev/null @@ -1,474 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# 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. - -""" -gettext for openstack-common modules. - -Usual usage in an openstack.common module: - - from graffiti.openstack.common.gettextutils import _ -""" - -import copy -import functools -import gettext -import locale -from logging import handlers -import os -import re - -from babel import localedata -import six - -_localedir = os.environ.get('graffiti'.upper() + '_LOCALEDIR') -_t = gettext.translation('graffiti', localedir=_localedir, fallback=True) - -# We use separate translation catalogs for each log level, so set up a -# mapping between the log level name and the translator. The domain -# for the log level is project_name + "-log-" + log_level so messages -# for each level end up in their own catalog. -_t_log_levels = dict( - (level, gettext.translation('graffiti' + '-log-' + level, - localedir=_localedir, - fallback=True)) - for level in ['info', 'warning', 'error', 'critical'] -) - -_AVAILABLE_LANGUAGES = {} -USE_LAZY = False - - -def enable_lazy(): - """Convenience function for configuring _() to use lazy gettext - - Call this at the start of execution to enable the gettextutils._ - function to use lazy gettext functionality. This is useful if - your project is importing _ directly instead of using the - gettextutils.install() way of importing the _ function. - """ - global USE_LAZY - USE_LAZY = True - - -def _(msg): - if USE_LAZY: - return Message(msg, domain='graffiti') - else: - if six.PY3: - return _t.gettext(msg) - return _t.ugettext(msg) - - -def _log_translation(msg, level): - """Build a single translation of a log message - """ - if USE_LAZY: - return Message(msg, domain='graffiti' + '-log-' + level) - else: - translator = _t_log_levels[level] - if six.PY3: - return translator.gettext(msg) - return translator.ugettext(msg) - -# Translators for log levels. -# -# The abbreviated names are meant to reflect the usual use of a short -# name like '_'. The "L" is for "log" and the other letter comes from -# the level. -_LI = functools.partial(_log_translation, level='info') -_LW = functools.partial(_log_translation, level='warning') -_LE = functools.partial(_log_translation, level='error') -_LC = functools.partial(_log_translation, level='critical') - - -def install(domain, lazy=False): - """Install a _() function using the given translation domain. - - Given a translation domain, install a _() function using gettext's - install() function. - - The main difference from gettext.install() is that we allow - overriding the default localedir (e.g. /usr/share/locale) using - a translation-domain-specific environment variable (e.g. - NOVA_LOCALEDIR). - - :param domain: the translation domain - :param lazy: indicates whether or not to install the lazy _() function. - The lazy _() introduces a way to do deferred translation - of messages by installing a _ that builds Message objects, - instead of strings, which can then be lazily translated into - any available locale. - """ - if lazy: - # NOTE(mrodden): Lazy gettext functionality. - # - # The following introduces a deferred way to do translations on - # messages in OpenStack. We override the standard _() function - # and % (format string) operation to build Message objects that can - # later be translated when we have more information. - def _lazy_gettext(msg): - """Create and return a Message object. - - Lazy gettext function for a given domain, it is a factory method - for a project/module to get a lazy gettext function for its own - translation domain (i.e. nova, glance, cinder, etc.) - - Message encapsulates a string so that we can translate - it later when needed. - """ - return Message(msg, domain=domain) - - from six import moves - moves.builtins.__dict__['_'] = _lazy_gettext - else: - localedir = '%s_LOCALEDIR' % domain.upper() - if six.PY3: - gettext.install(domain, - localedir=os.environ.get(localedir)) - else: - gettext.install(domain, - localedir=os.environ.get(localedir), - unicode=True) - - -class Message(six.text_type): - """A Message object is a unicode object that can be translated. - - Translation of Message is done explicitly using the translate() method. - For all non-translation intents and purposes, a Message is simply unicode, - and can be treated as such. - """ - - def __new__(cls, msgid, msgtext=None, params=None, - domain='graffiti', *args): - """Create a new Message object. - - In order for translation to work gettext requires a message ID, this - msgid will be used as the base unicode text. It is also possible - for the msgid and the base unicode text to be different by passing - the msgtext parameter. - """ - # If the base msgtext is not given, we use the default translation - # of the msgid (which is in English) just in case the system locale is - # not English, so that the base text will be in that locale by default. - if not msgtext: - msgtext = Message._translate_msgid(msgid, domain) - # We want to initialize the parent unicode with the actual object that - # would have been plain unicode if 'Message' was not enabled. - msg = super(Message, cls).__new__(cls, msgtext) - msg.msgid = msgid - msg.domain = domain - msg.params = params - return msg - - def translate(self, desired_locale=None): - """Translate this message to the desired locale. - - :param desired_locale: The desired locale to translate the message to, - if no locale is provided the message will be - translated to the system's default locale. - - :returns: the translated message in unicode - """ - - translated_message = Message._translate_msgid(self.msgid, - self.domain, - desired_locale) - if self.params is None: - # No need for more translation - return translated_message - - # This Message object may have been formatted with one or more - # Message objects as substitution arguments, given either as a single - # argument, part of a tuple, or as one or more values in a dictionary. - # When translating this Message we need to translate those Messages too - translated_params = _translate_args(self.params, desired_locale) - - translated_message = translated_message % translated_params - - return translated_message - - @staticmethod - def _translate_msgid(msgid, domain, desired_locale=None): - if not desired_locale: - system_locale = locale.getdefaultlocale() - # If the system locale is not available to the runtime use English - if not system_locale[0]: - desired_locale = 'en_US' - else: - desired_locale = system_locale[0] - - locale_dir = os.environ.get(domain.upper() + '_LOCALEDIR') - lang = gettext.translation(domain, - localedir=locale_dir, - languages=[desired_locale], - fallback=True) - if six.PY3: - translator = lang.gettext - else: - translator = lang.ugettext - - translated_message = translator(msgid) - return translated_message - - def __mod__(self, other): - # When we mod a Message we want the actual operation to be performed - # by the parent class (i.e. unicode()), the only thing we do here is - # save the original msgid and the parameters in case of a translation - params = self._sanitize_mod_params(other) - unicode_mod = super(Message, self).__mod__(params) - modded = Message(self.msgid, - msgtext=unicode_mod, - params=params, - domain=self.domain) - return modded - - def _sanitize_mod_params(self, other): - """Sanitize the object being modded with this Message. - - - Add support for modding 'None' so translation supports it - - Trim the modded object, which can be a large dictionary, to only - those keys that would actually be used in a translation - - Snapshot the object being modded, in case the message is - translated, it will be used as it was when the Message was created - """ - if other is None: - params = (other,) - elif isinstance(other, dict): - params = self._trim_dictionary_parameters(other) - else: - params = self._copy_param(other) - return params - - def _trim_dictionary_parameters(self, dict_param): - """Return a dict that only has matching entries in the msgid.""" - # NOTE(luisg): Here we trim down the dictionary passed as parameters - # to avoid carrying a lot of unnecessary weight around in the message - # object, for example if someone passes in Message() % locals() but - # only some params are used, and additionally we prevent errors for - # non-deepcopyable objects by unicoding() them. - - # Look for %(param) keys in msgid; - # Skip %% and deal with the case where % is first character on the line - keys = re.findall('(?:[^%]|^)?%\((\w*)\)[a-z]', self.msgid) - - # If we don't find any %(param) keys but have a %s - if not keys and re.findall('(?:[^%]|^)%[a-z]', self.msgid): - # Apparently the full dictionary is the parameter - params = self._copy_param(dict_param) - else: - params = {} - # Save our existing parameters as defaults to protect - # ourselves from losing values if we are called through an - # (erroneous) chain that builds a valid Message with - # arguments, and then does something like "msg % kwds" - # where kwds is an empty dictionary. - src = {} - if isinstance(self.params, dict): - src.update(self.params) - src.update(dict_param) - for key in keys: - params[key] = self._copy_param(src[key]) - - return params - - def _copy_param(self, param): - try: - return copy.deepcopy(param) - except TypeError: - # Fallback to casting to unicode this will handle the - # python code-like objects that can't be deep-copied - return six.text_type(param) - - def __add__(self, other): - msg = _('Message objects do not support addition.') - raise TypeError(msg) - - def __radd__(self, other): - return self.__add__(other) - - def __str__(self): - # NOTE(luisg): Logging in python 2.6 tries to str() log records, - # and it expects specifically a UnicodeError in order to proceed. - msg = _('Message objects do not support str() because they may ' - 'contain non-ascii characters. ' - 'Please use unicode() or translate() instead.') - raise UnicodeError(msg) - - -def get_available_languages(domain): - """Lists the available languages for the given translation domain. - - :param domain: the domain to get languages for - """ - if domain in _AVAILABLE_LANGUAGES: - return copy.copy(_AVAILABLE_LANGUAGES[domain]) - - localedir = '%s_LOCALEDIR' % domain.upper() - find = lambda x: gettext.find(domain, - localedir=os.environ.get(localedir), - languages=[x]) - - # NOTE(mrodden): en_US should always be available (and first in case - # order matters) since our in-line message strings are en_US - language_list = ['en_US'] - # NOTE(luisg): Babel <1.0 used a function called list(), which was - # renamed to locale_identifiers() in >=1.0, the requirements master list - # requires >=0.9.6, uncapped, so defensively work with both. We can remove - # this check when the master list updates to >=1.0, and update all projects - list_identifiers = (getattr(localedata, 'list', None) or - getattr(localedata, 'locale_identifiers')) - locale_identifiers = list_identifiers() - - for i in locale_identifiers: - if find(i) is not None: - language_list.append(i) - - # NOTE(luisg): Babel>=1.0,<1.3 has a bug where some OpenStack supported - # locales (e.g. 'zh_CN', and 'zh_TW') aren't supported even though they - # are perfectly legitimate locales: - # https://github.com/mitsuhiko/babel/issues/37 - # In Babel 1.3 they fixed the bug and they support these locales, but - # they are still not explicitly "listed" by locale_identifiers(). - # That is why we add the locales here explicitly if necessary so that - # they are listed as supported. - aliases = {'zh': 'zh_CN', - 'zh_Hant_HK': 'zh_HK', - 'zh_Hant': 'zh_TW', - 'fil': 'tl_PH'} - for (locale, alias) in six.iteritems(aliases): - if locale in language_list and alias not in language_list: - language_list.append(alias) - - _AVAILABLE_LANGUAGES[domain] = language_list - return copy.copy(language_list) - - -def translate(obj, desired_locale=None): - """Gets the translated unicode representation of the given object. - - If the object is not translatable it is returned as-is. - If the locale is None the object is translated to the system locale. - - :param obj: the object to translate - :param desired_locale: the locale to translate the message to, if None the - default system locale will be used - :returns: the translated object in unicode, or the original object if - it could not be translated - """ - message = obj - if not isinstance(message, Message): - # If the object to translate is not already translatable, - # let's first get its unicode representation - message = six.text_type(obj) - if isinstance(message, Message): - # Even after unicoding() we still need to check if we are - # running with translatable unicode before translating - return message.translate(desired_locale) - return obj - - -def _translate_args(args, desired_locale=None): - """Translates all the translatable elements of the given arguments object. - - This method is used for translating the translatable values in method - arguments which include values of tuples or dictionaries. - If the object is not a tuple or a dictionary the object itself is - translated if it is translatable. - - If the locale is None the object is translated to the system locale. - - :param args: the args to translate - :param desired_locale: the locale to translate the args to, if None the - default system locale will be used - :returns: a new args object with the translated contents of the original - """ - if isinstance(args, tuple): - return tuple(translate(v, desired_locale) for v in args) - if isinstance(args, dict): - translated_dict = {} - for (k, v) in six.iteritems(args): - translated_v = translate(v, desired_locale) - translated_dict[k] = translated_v - return translated_dict - return translate(args, desired_locale) - - -class TranslationHandler(handlers.MemoryHandler): - """Handler that translates records before logging them. - - The TranslationHandler takes a locale and a target logging.Handler object - to forward LogRecord objects to after translating them. This handler - depends on Message objects being logged, instead of regular strings. - - The handler can be configured declaratively in the logging.conf as follows: - - [handlers] - keys = translatedlog, translator - - [handler_translatedlog] - class = handlers.WatchedFileHandler - args = ('/var/log/api-localized.log',) - formatter = context - - [handler_translator] - class = openstack.common.log.TranslationHandler - target = translatedlog - args = ('zh_CN',) - - If the specified locale is not available in the system, the handler will - log in the default locale. - """ - - def __init__(self, locale=None, target=None): - """Initialize a TranslationHandler - - :param locale: locale to use for translating messages - :param target: logging.Handler object to forward - LogRecord objects to after translation - """ - # NOTE(luisg): In order to allow this handler to be a wrapper for - # other handlers, such as a FileHandler, and still be able to - # configure it using logging.conf, this handler has to extend - # MemoryHandler because only the MemoryHandlers' logging.conf - # parsing is implemented such that it accepts a target handler. - handlers.MemoryHandler.__init__(self, capacity=0, target=target) - self.locale = locale - - def setFormatter(self, fmt): - self.target.setFormatter(fmt) - - def emit(self, record): - # We save the message from the original record to restore it - # after translation, so other handlers are not affected by this - original_msg = record.msg - original_args = record.args - - try: - self._translate_and_log_record(record) - finally: - record.msg = original_msg - record.args = original_args - - def _translate_and_log_record(self, record): - record.msg = translate(record.msg, self.locale) - - # In addition to translating the message, we also need to translate - # arguments that were passed to the log method that were not part - # of the main message e.g., log.info(_('Some message %s'), this_one)) - record.args = _translate_args(record.args, self.locale) - - self.target.emit(record) diff --git a/graffiti/openstack/common/importutils.py b/graffiti/openstack/common/importutils.py deleted file mode 100644 index e8e60f4..0000000 --- a/graffiti/openstack/common/importutils.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# 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. - -""" -Import related utilities and helper functions. -""" - -import sys -import traceback - - -def import_class(import_str): - """Returns a class from a string including module and class.""" - mod_str, _sep, class_str = import_str.rpartition('.') - try: - __import__(mod_str) - return getattr(sys.modules[mod_str], class_str) - except (ValueError, AttributeError): - raise ImportError('Class %s cannot be found (%s)' % - (class_str, - traceback.format_exception(*sys.exc_info()))) - - -def import_object(import_str, *args, **kwargs): - """Import a class and return an instance of it.""" - return import_class(import_str)(*args, **kwargs) - - -def import_object_ns(name_space, import_str, *args, **kwargs): - """Tries to import object from default namespace. - - Imports a class and return an instance of it, first by trying - to find the class in a default namespace, then failing back to - a full path if not found in the default namespace. - """ - import_value = "%s.%s" % (name_space, import_str) - try: - return import_class(import_value)(*args, **kwargs) - except ImportError: - return import_class(import_str)(*args, **kwargs) - - -def import_module(import_str): - """Import a module.""" - __import__(import_str) - return sys.modules[import_str] - - -def import_versioned_module(version, submodule=None): - module = 'graffiti.v%s' % version - if submodule: - module = '.'.join((module, submodule)) - return import_module(module) - - -def try_import(import_str, default=None): - """Try to import a module and if it fails return default.""" - try: - return import_module(import_str) - except ImportError: - return default diff --git a/graffiti/openstack/common/jsonutils.py b/graffiti/openstack/common/jsonutils.py deleted file mode 100644 index 0d97691..0000000 --- a/graffiti/openstack/common/jsonutils.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# Copyright 2011 Justin Santa Barbara -# All Rights Reserved. -# -# 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. - -''' -JSON related utilities. - -This module provides a few things: - - 1) A handy function for getting an object down to something that can be - JSON serialized. See to_primitive(). - - 2) Wrappers around loads() and dumps(). The dumps() wrapper will - automatically use to_primitive() for you if needed. - - 3) This sets up anyjson to use the loads() and dumps() wrappers if anyjson - is available. -''' - - -import datetime -import functools -import inspect -import itertools -import json - -import six -import six.moves.xmlrpc_client as xmlrpclib - -from graffiti.openstack.common import gettextutils -from graffiti.openstack.common import importutils -from graffiti.openstack.common import timeutils - -netaddr = importutils.try_import("netaddr") - -_nasty_type_tests = [inspect.ismodule, inspect.isclass, inspect.ismethod, - inspect.isfunction, inspect.isgeneratorfunction, - inspect.isgenerator, inspect.istraceback, inspect.isframe, - inspect.iscode, inspect.isbuiltin, inspect.isroutine, - inspect.isabstract] - -_simple_types = (six.string_types + six.integer_types - + (type(None), bool, float)) - - -def to_primitive(value, convert_instances=False, convert_datetime=True, - level=0, max_depth=3): - """Convert a complex object into primitives. - - Handy for JSON serialization. We can optionally handle instances, - but since this is a recursive function, we could have cyclical - data structures. - - To handle cyclical data structures we could track the actual objects - visited in a set, but not all objects are hashable. Instead we just - track the depth of the object inspections and don't go too deep. - - Therefore, convert_instances=True is lossy ... be aware. - - """ - # handle obvious types first - order of basic types determined by running - # full tests on nova project, resulting in the following counts: - # 572754 - # 460353 - # 379632 - # 274610 - # 199918 - # 114200 - # 51817 - # 26164 - # 6491 - # 283 - # 19 - if isinstance(value, _simple_types): - return value - - if isinstance(value, datetime.datetime): - if convert_datetime: - return timeutils.strtime(value) - else: - return value - - # value of itertools.count doesn't get caught by nasty_type_tests - # and results in infinite loop when list(value) is called. - if type(value) == itertools.count: - return six.text_type(value) - - # FIXME(vish): Workaround for LP bug 852095. Without this workaround, - # tests that raise an exception in a mocked method that - # has a @wrap_exception with a notifier will fail. If - # we up the dependency to 0.5.4 (when it is released) we - # can remove this workaround. - if getattr(value, '__module__', None) == 'mox': - return 'mock' - - if level > max_depth: - return '?' - - # The try block may not be necessary after the class check above, - # but just in case ... - try: - recursive = functools.partial(to_primitive, - convert_instances=convert_instances, - convert_datetime=convert_datetime, - level=level, - max_depth=max_depth) - if isinstance(value, dict): - return dict((k, recursive(v)) for k, v in six.iteritems(value)) - elif isinstance(value, (list, tuple)): - return [recursive(lv) for lv in value] - - # It's not clear why xmlrpclib created their own DateTime type, but - # for our purposes, make it a datetime type which is explicitly - # handled - if isinstance(value, xmlrpclib.DateTime): - value = datetime.datetime(*tuple(value.timetuple())[:6]) - - if convert_datetime and isinstance(value, datetime.datetime): - return timeutils.strtime(value) - elif isinstance(value, gettextutils.Message): - return value.data - elif hasattr(value, 'iteritems'): - return recursive(dict(value.iteritems()), level=level + 1) - elif hasattr(value, '__iter__'): - return recursive(list(value)) - elif convert_instances and hasattr(value, '__dict__'): - # Likely an instance of something. Watch for cycles. - # Ignore class member vars. - return recursive(value.__dict__, level=level + 1) - elif netaddr and isinstance(value, netaddr.IPAddress): - return six.text_type(value) - else: - if any(test(value) for test in _nasty_type_tests): - return six.text_type(value) - return value - except TypeError: - # Class objects are tricky since they may define something like - # __iter__ defined but it isn't callable as list(). - return six.text_type(value) - - -def dumps(value, default=to_primitive, **kwargs): - return json.dumps(value, default=default, **kwargs) - - -def loads(s): - return json.loads(s) - - -def load(s): - return json.load(s) - - -try: - import anyjson -except ImportError: - pass -else: - anyjson._modules.append((__name__, 'dumps', TypeError, - 'loads', ValueError, 'load')) - anyjson.force_implementation(__name__) diff --git a/graffiti/openstack/common/local.py b/graffiti/openstack/common/local.py deleted file mode 100644 index 0819d5b..0000000 --- a/graffiti/openstack/common/local.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# 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. - -"""Local storage of variables using weak references""" - -import threading -import weakref - - -class WeakLocal(threading.local): - def __getattribute__(self, attr): - rval = super(WeakLocal, self).__getattribute__(attr) - if rval: - # NOTE(mikal): this bit is confusing. What is stored is a weak - # reference, not the value itself. We therefore need to lookup - # the weak reference and return the inner value here. - rval = rval() - return rval - - def __setattr__(self, attr, value): - value = weakref.ref(value) - return super(WeakLocal, self).__setattr__(attr, value) - - -# NOTE(mikal): the name "store" should be deprecated in the future -store = WeakLocal() - -# A "weak" store uses weak references and allows an object to fall out of scope -# when it falls out of scope in the code that uses the thread local storage. A -# "strong" store will hold a reference to the object so that it never falls out -# of scope. -weak_store = WeakLocal() -strong_store = threading.local() diff --git a/graffiti/openstack/common/lockutils.py b/graffiti/openstack/common/lockutils.py deleted file mode 100644 index 65e8106..0000000 --- a/graffiti/openstack/common/lockutils.py +++ /dev/null @@ -1,377 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# 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. - -import contextlib -import errno -import fcntl -import functools -import os -import shutil -import subprocess -import sys -import tempfile -import threading -import time -import weakref - -from oslo.config import cfg - -from graffiti.openstack.common import fileutils -from graffiti.openstack.common.gettextutils import _, _LE, _LI -from graffiti.openstack.common import log as logging - - -LOG = logging.getLogger(__name__) - - -util_opts = [ - cfg.BoolOpt('disable_process_locking', default=False, - help='Whether to disable inter-process locks'), - cfg.StrOpt('lock_path', - default=os.environ.get("GRAFFITI_LOCK_PATH"), - help=('Directory to use for lock files.')) -] - - -CONF = cfg.CONF -CONF.register_opts(util_opts) - - -def set_defaults(lock_path): - cfg.set_defaults(util_opts, lock_path=lock_path) - - -class _FileLock(object): - """Lock implementation which allows multiple locks, working around - issues like bugs.debian.org/cgi-bin/bugreport.cgi?bug=632857 and does - not require any cleanup. Since the lock is always held on a file - descriptor rather than outside of the process, the lock gets dropped - automatically if the process crashes, even if __exit__ is not executed. - - There are no guarantees regarding usage by multiple green threads in a - single process here. This lock works only between processes. Exclusive - access between local threads should be achieved using the semaphores - in the @synchronized decorator. - - Note these locks are released when the descriptor is closed, so it's not - safe to close the file descriptor while another green thread holds the - lock. Just opening and closing the lock file can break synchronisation, - so lock files must be accessed only using this abstraction. - """ - - def __init__(self, name): - self.lockfile = None - self.fname = name - - def acquire(self): - basedir = os.path.dirname(self.fname) - - if not os.path.exists(basedir): - fileutils.ensure_tree(basedir) - LOG.info(_LI('Created lock path: %s'), basedir) - - self.lockfile = open(self.fname, 'w') - - while True: - try: - # Using non-blocking locks since green threads are not - # patched to deal with blocking locking calls. - # Also upon reading the MSDN docs for locking(), it seems - # to have a laughable 10 attempts "blocking" mechanism. - self.trylock() - LOG.debug('Got file lock "%s"', self.fname) - return True - except IOError as e: - if e.errno in (errno.EACCES, errno.EAGAIN): - # external locks synchronise things like iptables - # updates - give it some time to prevent busy spinning - time.sleep(0.01) - else: - raise threading.ThreadError(_("Unable to acquire lock on" - " `%(filename)s` due to" - " %(exception)s") % - { - 'filename': self.fname, - 'exception': e, - }) - - def __enter__(self): - self.acquire() - return self - - def release(self): - try: - self.unlock() - self.lockfile.close() - LOG.debug('Released file lock "%s"', self.fname) - except IOError: - LOG.exception(_LE("Could not release the acquired lock `%s`"), - self.fname) - - def __exit__(self, exc_type, exc_val, exc_tb): - self.release() - - def exists(self): - return os.path.exists(self.fname) - - def trylock(self): - raise NotImplementedError() - - def unlock(self): - raise NotImplementedError() - - -class _WindowsLock(_FileLock): - def trylock(self): - msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_NBLCK, 1) - - def unlock(self): - msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_UNLCK, 1) - - -class _FcntlLock(_FileLock): - def trylock(self): - fcntl.lockf(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB) - - def unlock(self): - fcntl.lockf(self.lockfile, fcntl.LOCK_UN) - - -class _PosixLock(object): - def __init__(self, name): - # Hash the name because it's not valid to have POSIX semaphore - # names with things like / in them. Then use base64 to encode - # the digest() instead taking the hexdigest() because the - # result is shorter and most systems can't have shm sempahore - # names longer than 31 characters. - h = hashlib.sha1() - h.update(name.encode('ascii')) - self.name = str((b'/' + base64.urlsafe_b64encode( - h.digest())).decode('ascii')) - - def acquire(self, timeout=None): - self.semaphore = posix_ipc.Semaphore(self.name, - flags=posix_ipc.O_CREAT, - initial_value=1) - self.semaphore.acquire(timeout) - return self - - def __enter__(self): - self.acquire() - return self - - def release(self): - self.semaphore.release() - self.semaphore.close() - - def __exit__(self, exc_type, exc_val, exc_tb): - self.release() - - def exists(self): - try: - semaphore = posix_ipc.Semaphore(self.name) - except posix_ipc.ExistentialError: - return False - else: - semaphore.close() - return True - - -if os.name == 'nt': - import msvcrt - InterProcessLock = _WindowsLock - FileLock = _WindowsLock -else: - import base64 - import hashlib - import posix_ipc - InterProcessLock = _PosixLock - FileLock = _FcntlLock - -_semaphores = weakref.WeakValueDictionary() -_semaphores_lock = threading.Lock() - - -def _get_lock_path(name, lock_file_prefix, lock_path=None): - # NOTE(mikal): the lock name cannot contain directory - # separators - name = name.replace(os.sep, '_') - if lock_file_prefix: - sep = '' if lock_file_prefix.endswith('-') else '-' - name = '%s%s%s' % (lock_file_prefix, sep, name) - - local_lock_path = lock_path or CONF.lock_path - - if not local_lock_path: - # NOTE(bnemec): Create a fake lock path for posix locks so we don't - # unnecessarily raise the RequiredOptError below. - if InterProcessLock is not _PosixLock: - raise cfg.RequiredOptError('lock_path') - local_lock_path = 'posixlock:/' - - return os.path.join(local_lock_path, name) - - -def external_lock(name, lock_file_prefix=None, lock_path=None): - LOG.debug('Attempting to grab external lock "%(lock)s"', - {'lock': name}) - - lock_file_path = _get_lock_path(name, lock_file_prefix, lock_path) - - # NOTE(bnemec): If an explicit lock_path was passed to us then it - # means the caller is relying on file-based locking behavior, so - # we can't use posix locks for those calls. - if lock_path: - return FileLock(lock_file_path) - return InterProcessLock(lock_file_path) - - -def remove_external_lock_file(name, lock_file_prefix=None): - """Remove a external lock file when it's not used anymore - This will be helpful when we have a lot of lock files - """ - with internal_lock(name): - lock_file_path = _get_lock_path(name, lock_file_prefix) - try: - os.remove(lock_file_path) - except OSError: - LOG.info(_LI('Failed to remove file %(file)s'), - {'file': lock_file_path}) - - -def internal_lock(name): - with _semaphores_lock: - try: - sem = _semaphores[name] - except KeyError: - sem = threading.Semaphore() - _semaphores[name] = sem - - LOG.debug('Got semaphore "%(lock)s"', {'lock': name}) - return sem - - -@contextlib.contextmanager -def lock(name, lock_file_prefix=None, external=False, lock_path=None): - """Context based lock - - This function yields a `threading.Semaphore` instance (if we don't use - eventlet.monkey_patch(), else `semaphore.Semaphore`) unless external is - True, in which case, it'll yield an InterProcessLock instance. - - :param lock_file_prefix: The lock_file_prefix argument is used to provide - lock files on disk with a meaningful prefix. - - :param external: The external keyword argument denotes whether this lock - should work across multiple processes. This means that if two different - workers both run a a method decorated with @synchronized('mylock', - external=True), only one of them will execute at a time. - """ - int_lock = internal_lock(name) - with int_lock: - if external and not CONF.disable_process_locking: - ext_lock = external_lock(name, lock_file_prefix, lock_path) - with ext_lock: - yield ext_lock - else: - yield int_lock - - -def synchronized(name, lock_file_prefix=None, external=False, lock_path=None): - """Synchronization decorator. - - Decorating a method like so:: - - @synchronized('mylock') - def foo(self, *args): - ... - - ensures that only one thread will execute the foo method at a time. - - Different methods can share the same lock:: - - @synchronized('mylock') - def foo(self, *args): - ... - - @synchronized('mylock') - def bar(self, *args): - ... - - This way only one of either foo or bar can be executing at a time. - """ - - def wrap(f): - @functools.wraps(f) - def inner(*args, **kwargs): - try: - with lock(name, lock_file_prefix, external, lock_path): - LOG.debug('Got semaphore / lock "%(function)s"', - {'function': f.__name__}) - return f(*args, **kwargs) - finally: - LOG.debug('Semaphore / lock released "%(function)s"', - {'function': f.__name__}) - return inner - return wrap - - -def synchronized_with_prefix(lock_file_prefix): - """Partial object generator for the synchronization decorator. - - Redefine @synchronized in each project like so:: - - (in nova/utils.py) - from nova.openstack.common import lockutils - - synchronized = lockutils.synchronized_with_prefix('nova-') - - - (in nova/foo.py) - from nova import utils - - @utils.synchronized('mylock') - def bar(self, *args): - ... - - The lock_file_prefix argument is used to provide lock files on disk with a - meaningful prefix. - """ - - return functools.partial(synchronized, lock_file_prefix=lock_file_prefix) - - -def main(argv): - """Create a dir for locks and pass it to command from arguments - - If you run this: - python -m openstack.common.lockutils python setup.py testr - - a temporary directory will be created for all your locks and passed to all - your tests in an environment variable. The temporary dir will be deleted - afterwards and the return value will be preserved. - """ - - lock_dir = tempfile.mkdtemp() - os.environ["GRAFFITI_LOCK_PATH"] = lock_dir - try: - ret_val = subprocess.call(argv[1:]) - finally: - shutil.rmtree(lock_dir, ignore_errors=True) - return ret_val - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/graffiti/openstack/common/log.py b/graffiti/openstack/common/log.py deleted file mode 100644 index 3986347..0000000 --- a/graffiti/openstack/common/log.py +++ /dev/null @@ -1,711 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# 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. - -"""OpenStack logging handler. - -This module adds to logging functionality by adding the option to specify -a context object when calling the various log methods. If the context object -is not specified, default formatting is used. Additionally, an instance uuid -may be passed as part of the log message, which is intended to make it easier -for admins to find messages related to a specific instance. - -It also allows setting of formatting information through conf. - -""" - -import inspect -import itertools -import logging -import logging.config -import logging.handlers -import os -import re -import sys -import traceback - -from oslo.config import cfg -import six -from six import moves - -from graffiti.openstack.common.gettextutils import _ -from graffiti.openstack.common import importutils -from graffiti.openstack.common import jsonutils -from graffiti.openstack.common import local - - -_DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S" - -_SANITIZE_KEYS = ['adminPass', 'admin_pass', 'password', 'admin_password'] - -# NOTE(ldbragst): Let's build a list of regex objects using the list of -# _SANITIZE_KEYS we already have. This way, we only have to add the new key -# to the list of _SANITIZE_KEYS and we can generate regular expressions -# for XML and JSON automatically. -_SANITIZE_PATTERNS = [] -_FORMAT_PATTERNS = [r'(%(key)s\s*[=]\s*[\"\']).*?([\"\'])', - r'(<%(key)s>).*?()', - r'([\"\']%(key)s[\"\']\s*:\s*[\"\']).*?([\"\'])', - r'([\'"].*?%(key)s[\'"]\s*:\s*u?[\'"]).*?([\'"])'] - -for key in _SANITIZE_KEYS: - for pattern in _FORMAT_PATTERNS: - reg_ex = re.compile(pattern % {'key': key}, re.DOTALL) - _SANITIZE_PATTERNS.append(reg_ex) - - -common_cli_opts = [ - cfg.BoolOpt('debug', - short='d', - default=False, - help='Print debugging output (set logging level to ' - 'DEBUG instead of default WARNING level).'), - cfg.BoolOpt('verbose', - short='v', - default=False, - help='Print more verbose output (set logging level to ' - 'INFO instead of default WARNING level).'), -] - -logging_cli_opts = [ - cfg.StrOpt('log-config-append', - metavar='PATH', - deprecated_name='log-config', - help='The name of logging configuration file. It does not ' - 'disable existing loggers, but just appends specified ' - 'logging configuration to any other existing logging ' - 'options. Please see the Python logging module ' - 'documentation for details on logging configuration ' - 'files.'), - cfg.StrOpt('log-format', - default=None, - metavar='FORMAT', - help='DEPRECATED. ' - 'A logging.Formatter log message format string which may ' - 'use any of the available logging.LogRecord attributes. ' - 'This option is deprecated. Please use ' - 'logging_context_format_string and ' - 'logging_default_format_string instead.'), - cfg.StrOpt('log-date-format', - default=_DEFAULT_LOG_DATE_FORMAT, - metavar='DATE_FORMAT', - help='Format string for %%(asctime)s in log records. ' - 'Default: %(default)s'), - cfg.StrOpt('log-file', - metavar='PATH', - deprecated_name='logfile', - help='(Optional) Name of log file to output to. ' - 'If no default is set, logging will go to stdout.'), - cfg.StrOpt('log-dir', - deprecated_name='logdir', - help='(Optional) The base directory used for relative ' - '--log-file paths'), - cfg.BoolOpt('use-syslog', - default=False, - help='Use syslog for logging. ' - 'Existing syslog format is DEPRECATED during I, ' - 'and then will be changed in J to honor RFC5424'), - cfg.BoolOpt('use-syslog-rfc-format', - # TODO(bogdando) remove or use True after existing - # syslog format deprecation in J - default=False, - help='(Optional) Use syslog rfc5424 format for logging. ' - 'If enabled, will add APP-NAME (RFC5424) before the ' - 'MSG part of the syslog message. The old format ' - 'without APP-NAME is deprecated in I, ' - 'and will be removed in J.'), - cfg.StrOpt('syslog-log-facility', - default='LOG_USER', - help='Syslog facility to receive log lines') -] - -generic_log_opts = [ - cfg.BoolOpt('use_stderr', - default=True, - help='Log output to standard error') -] - -log_opts = [ - cfg.StrOpt('logging_context_format_string', - default='%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' - '%(name)s [%(request_id)s %(user_identity)s] ' - '%(instance)s%(message)s', - help='Format string to use for log messages with context'), - cfg.StrOpt('logging_default_format_string', - default='%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' - '%(name)s [-] %(instance)s%(message)s', - help='Format string to use for log messages without context'), - cfg.StrOpt('logging_debug_format_suffix', - default='%(funcName)s %(pathname)s:%(lineno)d', - help='Data to append to log format when level is DEBUG'), - cfg.StrOpt('logging_exception_prefix', - default='%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s ' - '%(instance)s', - help='Prefix each line of exception output with this format'), - cfg.ListOpt('default_log_levels', - default=[ - 'amqp=WARN', - 'amqplib=WARN', - 'boto=WARN', - 'qpid=WARN', - 'sqlalchemy=WARN', - 'suds=INFO', - 'iso8601=WARN', - 'requests.packages.urllib3.connectionpool=WARN' - ], - help='List of logger=LEVEL pairs'), - cfg.BoolOpt('publish_errors', - default=False, - help='Publish error events'), - cfg.BoolOpt('fatal_deprecations', - default=False, - help='Make deprecations fatal'), - - # NOTE(mikal): there are two options here because sometimes we are handed - # a full instance (and could include more information), and other times we - # are just handed a UUID for the instance. - cfg.StrOpt('instance_format', - default='[instance: %(uuid)s] ', - help='If an instance is passed with the log message, format ' - 'it like this'), - cfg.StrOpt('instance_uuid_format', - default='[instance: %(uuid)s] ', - help='If an instance UUID is passed with the log message, ' - 'format it like this'), -] - -CONF = cfg.CONF -CONF.register_cli_opts(common_cli_opts) -CONF.register_cli_opts(logging_cli_opts) -CONF.register_opts(generic_log_opts) -CONF.register_opts(log_opts) - -# our new audit level -# NOTE(jkoelker) Since we synthesized an audit level, make the logging -# module aware of it so it acts like other levels. -logging.AUDIT = logging.INFO + 1 -logging.addLevelName(logging.AUDIT, 'AUDIT') - - -try: - NullHandler = logging.NullHandler -except AttributeError: # NOTE(jkoelker) NullHandler added in Python 2.7 - class NullHandler(logging.Handler): - def handle(self, record): - pass - - def emit(self, record): - pass - - def createLock(self): - self.lock = None - - -def _dictify_context(context): - if context is None: - return None - if not isinstance(context, dict) and getattr(context, 'to_dict', None): - context = context.to_dict() - return context - - -def _get_binary_name(): - return os.path.basename(inspect.stack()[-1][1]) - - -def _get_log_file_path(binary=None): - logfile = CONF.log_file - logdir = CONF.log_dir - - if logfile and not logdir: - return logfile - - if logfile and logdir: - return os.path.join(logdir, logfile) - - if logdir: - binary = binary or _get_binary_name() - return '%s.log' % (os.path.join(logdir, binary),) - - return None - - -def mask_password(message, secret="***"): - """Replace password with 'secret' in message. - - :param message: The string which includes security information. - :param secret: value with which to replace passwords. - :returns: The unicode value of message with the password fields masked. - - For example: - - >>> mask_password("'adminPass' : 'aaaaa'") - "'adminPass' : '***'" - >>> mask_password("'admin_pass' : 'aaaaa'") - "'admin_pass' : '***'" - >>> mask_password('"password" : "aaaaa"') - '"password" : "***"' - >>> mask_password("'original_password' : 'aaaaa'") - "'original_password' : '***'" - >>> mask_password("u'original_password' : u'aaaaa'") - "u'original_password' : u'***'" - """ - message = six.text_type(message) - - # NOTE(ldbragst): Check to see if anything in message contains any key - # specified in _SANITIZE_KEYS, if not then just return the message since - # we don't have to mask any passwords. - if not any(key in message for key in _SANITIZE_KEYS): - return message - - secret = r'\g<1>' + secret + r'\g<2>' - for pattern in _SANITIZE_PATTERNS: - message = re.sub(pattern, secret, message) - return message - - -class BaseLoggerAdapter(logging.LoggerAdapter): - - def audit(self, msg, *args, **kwargs): - self.log(logging.AUDIT, msg, *args, **kwargs) - - -class LazyAdapter(BaseLoggerAdapter): - def __init__(self, name='unknown', version='unknown'): - self._logger = None - self.extra = {} - self.name = name - self.version = version - - @property - def logger(self): - if not self._logger: - self._logger = getLogger(self.name, self.version) - return self._logger - - -class ContextAdapter(BaseLoggerAdapter): - warn = logging.LoggerAdapter.warning - - def __init__(self, logger, project_name, version_string): - self.logger = logger - self.project = project_name - self.version = version_string - self._deprecated_messages_sent = dict() - - @property - def handlers(self): - return self.logger.handlers - - def deprecated(self, msg, *args, **kwargs): - """Call this method when a deprecated feature is used. - - If the system is configured for fatal deprecations then the message - is logged at the 'critical' level and :class:`DeprecatedConfig` will - be raised. - - Otherwise, the message will be logged (once) at the 'warn' level. - - :raises: :class:`DeprecatedConfig` if the system is configured for - fatal deprecations. - - """ - stdmsg = _("Deprecated: %s") % msg - if CONF.fatal_deprecations: - self.critical(stdmsg, *args, **kwargs) - raise DeprecatedConfig(msg=stdmsg) - - # Using a list because a tuple with dict can't be stored in a set. - sent_args = self._deprecated_messages_sent.setdefault(msg, list()) - - if args in sent_args: - # Already logged this message, so don't log it again. - return - - sent_args.append(args) - self.warn(stdmsg, *args, **kwargs) - - def process(self, msg, kwargs): - # NOTE(mrodden): catch any Message/other object and - # coerce to unicode before they can get - # to the python logging and possibly - # cause string encoding trouble - if not isinstance(msg, six.string_types): - msg = six.text_type(msg) - - if 'extra' not in kwargs: - kwargs['extra'] = {} - extra = kwargs['extra'] - - context = kwargs.pop('context', None) - if not context: - context = getattr(local.store, 'context', None) - if context: - extra.update(_dictify_context(context)) - - instance = kwargs.pop('instance', None) - instance_uuid = (extra.get('instance_uuid') or - kwargs.pop('instance_uuid', None)) - instance_extra = '' - if instance: - instance_extra = CONF.instance_format % instance - elif instance_uuid: - instance_extra = (CONF.instance_uuid_format - % {'uuid': instance_uuid}) - extra['instance'] = instance_extra - - extra.setdefault('user_identity', kwargs.pop('user_identity', None)) - - extra['project'] = self.project - extra['version'] = self.version - extra['extra'] = extra.copy() - return msg, kwargs - - -class JSONFormatter(logging.Formatter): - def __init__(self, fmt=None, datefmt=None): - # NOTE(jkoelker) we ignore the fmt argument, but its still there - # since logging.config.fileConfig passes it. - self.datefmt = datefmt - - def formatException(self, ei, strip_newlines=True): - lines = traceback.format_exception(*ei) - if strip_newlines: - lines = [moves.filter( - lambda x: x, - line.rstrip().splitlines()) for line in lines] - lines = list(itertools.chain(*lines)) - return lines - - def format(self, record): - message = {'message': record.getMessage(), - 'asctime': self.formatTime(record, self.datefmt), - 'name': record.name, - 'msg': record.msg, - 'args': record.args, - 'levelname': record.levelname, - 'levelno': record.levelno, - 'pathname': record.pathname, - 'filename': record.filename, - 'module': record.module, - 'lineno': record.lineno, - 'funcname': record.funcName, - 'created': record.created, - 'msecs': record.msecs, - 'relative_created': record.relativeCreated, - 'thread': record.thread, - 'thread_name': record.threadName, - 'process_name': record.processName, - 'process': record.process, - 'traceback': None} - - if hasattr(record, 'extra'): - message['extra'] = record.extra - - if record.exc_info: - message['traceback'] = self.formatException(record.exc_info) - - return jsonutils.dumps(message) - - -def _create_logging_excepthook(product_name): - def logging_excepthook(exc_type, value, tb): - extra = {} - if CONF.verbose or CONF.debug: - extra['exc_info'] = (exc_type, value, tb) - getLogger(product_name).critical( - "".join(traceback.format_exception_only(exc_type, value)), - **extra) - return logging_excepthook - - -class LogConfigError(Exception): - - message = _('Error loading logging config %(log_config)s: %(err_msg)s') - - def __init__(self, log_config, err_msg): - self.log_config = log_config - self.err_msg = err_msg - - def __str__(self): - return self.message % dict(log_config=self.log_config, - err_msg=self.err_msg) - - -def _load_log_config(log_config_append): - try: - logging.config.fileConfig(log_config_append, - disable_existing_loggers=False) - except moves.configparser.Error as exc: - raise LogConfigError(log_config_append, str(exc)) - - -def setup(product_name, version='unknown'): - """Setup logging.""" - if CONF.log_config_append: - _load_log_config(CONF.log_config_append) - else: - _setup_logging_from_conf(product_name, version) - sys.excepthook = _create_logging_excepthook(product_name) - - -def set_defaults(logging_context_format_string): - cfg.set_defaults(log_opts, - logging_context_format_string=logging_context_format_string) - - -def _find_facility_from_conf(): - facility_names = logging.handlers.SysLogHandler.facility_names - facility = getattr(logging.handlers.SysLogHandler, - CONF.syslog_log_facility, - None) - - if facility is None and CONF.syslog_log_facility in facility_names: - facility = facility_names.get(CONF.syslog_log_facility) - - if facility is None: - valid_facilities = facility_names.keys() - consts = ['LOG_AUTH', 'LOG_AUTHPRIV', 'LOG_CRON', 'LOG_DAEMON', - 'LOG_FTP', 'LOG_KERN', 'LOG_LPR', 'LOG_MAIL', 'LOG_NEWS', - 'LOG_AUTH', 'LOG_SYSLOG', 'LOG_USER', 'LOG_UUCP', - 'LOG_LOCAL0', 'LOG_LOCAL1', 'LOG_LOCAL2', 'LOG_LOCAL3', - 'LOG_LOCAL4', 'LOG_LOCAL5', 'LOG_LOCAL6', 'LOG_LOCAL7'] - valid_facilities.extend(consts) - raise TypeError(_('syslog facility must be one of: %s') % - ', '.join("'%s'" % fac - for fac in valid_facilities)) - - return facility - - -class RFCSysLogHandler(logging.handlers.SysLogHandler): - def __init__(self, *args, **kwargs): - self.binary_name = _get_binary_name() - super(RFCSysLogHandler, self).__init__(*args, **kwargs) - - def format(self, record): - msg = super(RFCSysLogHandler, self).format(record) - msg = self.binary_name + ' ' + msg - return msg - - -def _setup_logging_from_conf(project, version): - log_root = getLogger(None).logger - for handler in log_root.handlers: - log_root.removeHandler(handler) - - if CONF.use_syslog: - facility = _find_facility_from_conf() - # TODO(bogdando) use the format provided by RFCSysLogHandler - # after existing syslog format deprecation in J - if CONF.use_syslog_rfc_format: - syslog = RFCSysLogHandler(address='/dev/log', - facility=facility) - else: - syslog = logging.handlers.SysLogHandler(address='/dev/log', - facility=facility) - log_root.addHandler(syslog) - - logpath = _get_log_file_path() - if logpath: - filelog = logging.handlers.WatchedFileHandler(logpath) - log_root.addHandler(filelog) - - if CONF.use_stderr: - streamlog = ColorHandler() - log_root.addHandler(streamlog) - - elif not logpath: - # pass sys.stdout as a positional argument - # python2.6 calls the argument strm, in 2.7 it's stream - streamlog = logging.StreamHandler(sys.stdout) - log_root.addHandler(streamlog) - - if CONF.publish_errors: - handler = importutils.import_object( - "graffiti.openstack.common.log_handler.PublishErrorsHandler", - logging.ERROR) - log_root.addHandler(handler) - - datefmt = CONF.log_date_format - for handler in log_root.handlers: - # NOTE(alaski): CONF.log_format overrides everything currently. This - # should be deprecated in favor of context aware formatting. - if CONF.log_format: - handler.setFormatter(logging.Formatter(fmt=CONF.log_format, - datefmt=datefmt)) - log_root.info('Deprecated: log_format is now deprecated and will ' - 'be removed in the next release') - else: - handler.setFormatter(ContextFormatter(project=project, - version=version, - datefmt=datefmt)) - - if CONF.debug: - log_root.setLevel(logging.DEBUG) - elif CONF.verbose: - log_root.setLevel(logging.INFO) - else: - log_root.setLevel(logging.WARNING) - - for pair in CONF.default_log_levels: - mod, _sep, level_name = pair.partition('=') - level = logging.getLevelName(level_name) - logger = logging.getLogger(mod) - logger.setLevel(level) - -_loggers = {} - - -def getLogger(name='unknown', version='unknown'): - if name not in _loggers: - _loggers[name] = ContextAdapter(logging.getLogger(name), - name, - version) - return _loggers[name] - - -def getLazyLogger(name='unknown', version='unknown'): - """Returns lazy logger. - - Creates a pass-through logger that does not create the real logger - until it is really needed and delegates all calls to the real logger - once it is created. - """ - return LazyAdapter(name, version) - - -class WritableLogger(object): - """A thin wrapper that responds to `write` and logs.""" - - def __init__(self, logger, level=logging.INFO): - self.logger = logger - self.level = level - - def write(self, msg): - self.logger.log(self.level, msg.rstrip()) - - -class ContextFormatter(logging.Formatter): - """A context.RequestContext aware formatter configured through flags. - - The flags used to set format strings are: logging_context_format_string - and logging_default_format_string. You can also specify - logging_debug_format_suffix to append extra formatting if the log level is - debug. - - For information about what variables are available for the formatter see: - http://docs.python.org/library/logging.html#formatter - - If available, uses the context value stored in TLS - local.store.context - - """ - - def __init__(self, *args, **kwargs): - """Initialize ContextFormatter instance - - Takes additional keyword arguments which can be used in the message - format string. - - :keyword project: project name - :type project: string - :keyword version: project version - :type version: string - - """ - - self.project = kwargs.pop('project', 'unknown') - self.version = kwargs.pop('version', 'unknown') - - logging.Formatter.__init__(self, *args, **kwargs) - - def format(self, record): - """Uses contextstring if request_id is set, otherwise default.""" - - # store project info - record.project = self.project - record.version = self.version - - # store request info - context = getattr(local.store, 'context', None) - if context: - d = _dictify_context(context) - for k, v in d.items(): - setattr(record, k, v) - - # NOTE(sdague): default the fancier formatting params - # to an empty string so we don't throw an exception if - # they get used - for key in ('instance', 'color'): - if key not in record.__dict__: - record.__dict__[key] = '' - - if record.__dict__.get('request_id'): - self._fmt = CONF.logging_context_format_string - else: - self._fmt = CONF.logging_default_format_string - - if (record.levelno == logging.DEBUG and - CONF.logging_debug_format_suffix): - self._fmt += " " + CONF.logging_debug_format_suffix - - # Cache this on the record, Logger will respect our formatted copy - if record.exc_info: - record.exc_text = self.formatException(record.exc_info, record) - return logging.Formatter.format(self, record) - - def formatException(self, exc_info, record=None): - """Format exception output with CONF.logging_exception_prefix.""" - if not record: - return logging.Formatter.formatException(self, exc_info) - - stringbuffer = moves.StringIO() - traceback.print_exception(exc_info[0], exc_info[1], exc_info[2], - None, stringbuffer) - lines = stringbuffer.getvalue().split('\n') - stringbuffer.close() - - if CONF.logging_exception_prefix.find('%(asctime)') != -1: - record.asctime = self.formatTime(record, self.datefmt) - - formatted_lines = [] - for line in lines: - pl = CONF.logging_exception_prefix % record.__dict__ - fl = '%s%s' % (pl, line) - formatted_lines.append(fl) - return '\n'.join(formatted_lines) - - -class ColorHandler(logging.StreamHandler): - LEVEL_COLORS = { - logging.DEBUG: '\033[00;32m', # GREEN - logging.INFO: '\033[00;36m', # CYAN - logging.AUDIT: '\033[01;36m', # BOLD CYAN - logging.WARN: '\033[01;33m', # BOLD YELLOW - logging.ERROR: '\033[01;31m', # BOLD RED - logging.CRITICAL: '\033[01;31m', # BOLD RED - } - - def format(self, record): - record.color = self.LEVEL_COLORS[record.levelno] - return logging.StreamHandler.format(self, record) - - -class DeprecatedConfig(Exception): - message = _("Fatal call to deprecated config: %(msg)s") - - def __init__(self, msg): - super(Exception, self).__init__(self.message % dict(msg=msg)) diff --git a/graffiti/openstack/common/processutils.py b/graffiti/openstack/common/processutils.py deleted file mode 100644 index 91c7f59..0000000 --- a/graffiti/openstack/common/processutils.py +++ /dev/null @@ -1,267 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# 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. - -""" -System-level utilities and helper functions. -""" - -import errno -import logging as stdlib_logging -import os -import random -import shlex -import signal - -from eventlet.green import subprocess -from eventlet import greenthread -import six - -from graffiti.openstack.common.gettextutils import _ -from graffiti.openstack.common import log as logging - - -LOG = logging.getLogger(__name__) - - -class InvalidArgumentError(Exception): - def __init__(self, message=None): - super(InvalidArgumentError, self).__init__(message) - - -class UnknownArgumentError(Exception): - def __init__(self, message=None): - super(UnknownArgumentError, self).__init__(message) - - -class ProcessExecutionError(Exception): - def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None, - description=None): - self.exit_code = exit_code - self.stderr = stderr - self.stdout = stdout - self.cmd = cmd - self.description = description - - if description is None: - description = _("Unexpected error while running command.") - if exit_code is None: - exit_code = '-' - message = _('%(description)s\n' - 'Command: %(cmd)s\n' - 'Exit code: %(exit_code)s\n' - 'Stdout: %(stdout)r\n' - 'Stderr: %(stderr)r') % {'description': description, - 'cmd': cmd, - 'exit_code': exit_code, - 'stdout': stdout, - 'stderr': stderr} - super(ProcessExecutionError, self).__init__(message) - - -class NoRootWrapSpecified(Exception): - def __init__(self, message=None): - super(NoRootWrapSpecified, self).__init__(message) - - -def _subprocess_setup(): - # Python installs a SIGPIPE handler by default. This is usually not what - # non-Python subprocesses expect. - signal.signal(signal.SIGPIPE, signal.SIG_DFL) - - -def execute(*cmd, **kwargs): - """Helper method to shell out and execute a command through subprocess. - - Allows optional retry. - - :param cmd: Passed to subprocess.Popen. - :type cmd: string - :param process_input: Send to opened process. - :type process_input: string - :param check_exit_code: Single bool, int, or list of allowed exit - codes. Defaults to [0]. Raise - :class:`ProcessExecutionError` unless - program exits with one of these code. - :type check_exit_code: boolean, int, or [int] - :param delay_on_retry: True | False. Defaults to True. If set to True, - wait a short amount of time before retrying. - :type delay_on_retry: boolean - :param attempts: How many times to retry cmd. - :type attempts: int - :param run_as_root: True | False. Defaults to False. If set to True, - the command is prefixed by the command specified - in the root_helper kwarg. - :type run_as_root: boolean - :param root_helper: command to prefix to commands called with - run_as_root=True - :type root_helper: string - :param shell: whether or not there should be a shell used to - execute this command. Defaults to false. - :type shell: boolean - :param loglevel: log level for execute commands. - :type loglevel: int. (Should be stdlib_logging.DEBUG or - stdlib_logging.INFO) - :returns: (stdout, stderr) from process execution - :raises: :class:`UnknownArgumentError` on - receiving unknown arguments - :raises: :class:`ProcessExecutionError` - """ - - process_input = kwargs.pop('process_input', None) - check_exit_code = kwargs.pop('check_exit_code', [0]) - ignore_exit_code = False - delay_on_retry = kwargs.pop('delay_on_retry', True) - attempts = kwargs.pop('attempts', 1) - run_as_root = kwargs.pop('run_as_root', False) - root_helper = kwargs.pop('root_helper', '') - shell = kwargs.pop('shell', False) - loglevel = kwargs.pop('loglevel', stdlib_logging.DEBUG) - - if isinstance(check_exit_code, bool): - ignore_exit_code = not check_exit_code - check_exit_code = [0] - elif isinstance(check_exit_code, int): - check_exit_code = [check_exit_code] - - if kwargs: - raise UnknownArgumentError(_('Got unknown keyword args ' - 'to utils.execute: %r') % kwargs) - - if run_as_root and hasattr(os, 'geteuid') and os.geteuid() != 0: - if not root_helper: - raise NoRootWrapSpecified( - message=_('Command requested root, but did not ' - 'specify a root helper.')) - cmd = shlex.split(root_helper) + list(cmd) - - cmd = map(str, cmd) - - while attempts > 0: - attempts -= 1 - try: - LOG.log(loglevel, 'Running cmd (subprocess): %s', - ' '.join(cmd)) - _PIPE = subprocess.PIPE # pylint: disable=E1101 - - if os.name == 'nt': - preexec_fn = None - close_fds = False - else: - preexec_fn = _subprocess_setup - close_fds = True - - obj = subprocess.Popen(cmd, - stdin=_PIPE, - stdout=_PIPE, - stderr=_PIPE, - close_fds=close_fds, - preexec_fn=preexec_fn, - shell=shell) - result = None - for _i in six.moves.range(20): - # NOTE(russellb) 20 is an arbitrary number of retries to - # prevent any chance of looping forever here. - try: - if process_input is not None: - result = obj.communicate(process_input) - else: - result = obj.communicate() - except OSError as e: - if e.errno in (errno.EAGAIN, errno.EINTR): - continue - raise - break - obj.stdin.close() # pylint: disable=E1101 - _returncode = obj.returncode # pylint: disable=E1101 - LOG.log(loglevel, 'Result was %s' % _returncode) - if not ignore_exit_code and _returncode not in check_exit_code: - (stdout, stderr) = result - raise ProcessExecutionError(exit_code=_returncode, - stdout=stdout, - stderr=stderr, - cmd=' '.join(cmd)) - return result - except ProcessExecutionError: - if not attempts: - raise - else: - LOG.log(loglevel, '%r failed. Retrying.', cmd) - if delay_on_retry: - greenthread.sleep(random.randint(20, 200) / 100.0) - finally: - # NOTE(termie): this appears to be necessary to let the subprocess - # call clean something up in between calls, without - # it two execute calls in a row hangs the second one - greenthread.sleep(0) - - -def trycmd(*args, **kwargs): - """A wrapper around execute() to more easily handle warnings and errors. - - Returns an (out, err) tuple of strings containing the output of - the command's stdout and stderr. If 'err' is not empty then the - command can be considered to have failed. - - :discard_warnings True | False. Defaults to False. If set to True, - then for succeeding commands, stderr is cleared - - """ - discard_warnings = kwargs.pop('discard_warnings', False) - - try: - out, err = execute(*args, **kwargs) - failed = False - except ProcessExecutionError as exn: - out, err = '', str(exn) - failed = True - - if not failed and discard_warnings and err: - # Handle commands that output to stderr but otherwise succeed - err = '' - - return out, err - - -def ssh_execute(ssh, cmd, process_input=None, - addl_env=None, check_exit_code=True): - LOG.debug('Running cmd (SSH): %s', cmd) - if addl_env: - raise InvalidArgumentError(_('Environment not supported over SSH')) - - if process_input: - # This is (probably) fixable if we need it... - raise InvalidArgumentError(_('process_input not supported over SSH')) - - stdin_stream, stdout_stream, stderr_stream = ssh.exec_command(cmd) - channel = stdout_stream.channel - - # NOTE(justinsb): This seems suspicious... - # ...other SSH clients have buffering issues with this approach - stdout = stdout_stream.read() - stderr = stderr_stream.read() - stdin_stream.close() - - exit_status = channel.recv_exit_status() - - # exit_status == -1 if no exit code was returned - if exit_status != -1: - LOG.debug('Result was %s' % exit_status) - if check_exit_code and exit_status != 0: - raise ProcessExecutionError(exit_code=exit_status, - stdout=stdout, - stderr=stderr, - cmd=cmd) - - return (stdout, stderr) diff --git a/graffiti/openstack/common/test.py b/graffiti/openstack/common/test.py deleted file mode 100644 index acb8aa2..0000000 --- a/graffiti/openstack/common/test.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# All Rights Reserved. -# -# 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. - -############################################################################## -############################################################################## -## -## DO NOT MODIFY THIS FILE -## -## This file is being graduated to the graffiti test library. Please make all -## changes there, and only backport critical fixes here. - dhellmann -## -############################################################################## -############################################################################## - -"""Common utilities used in testing""" - -import logging -import os -import tempfile - -import fixtures -import testtools - -_TRUE_VALUES = ('True', 'true', '1', 'yes') -_LOG_FORMAT = "%(levelname)8s [%(name)s] %(message)s" - - -class BaseTestCase(testtools.TestCase): - - def setUp(self): - super(BaseTestCase, self).setUp() - self._set_timeout() - self._fake_output() - self._fake_logs() - self.useFixture(fixtures.NestedTempfile()) - self.useFixture(fixtures.TempHomeDir()) - self.tempdirs = [] - - def _set_timeout(self): - test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0) - try: - test_timeout = int(test_timeout) - except ValueError: - # If timeout value is invalid do not set a timeout. - test_timeout = 0 - if test_timeout > 0: - self.useFixture(fixtures.Timeout(test_timeout, gentle=True)) - - def _fake_output(self): - if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES: - stdout = self.useFixture(fixtures.StringStream('stdout')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) - if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES: - stderr = self.useFixture(fixtures.StringStream('stderr')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) - - def _fake_logs(self): - if os.environ.get('OS_DEBUG') in _TRUE_VALUES: - level = logging.DEBUG - else: - level = logging.INFO - capture_logs = os.environ.get('OS_LOG_CAPTURE') in _TRUE_VALUES - if capture_logs: - self.useFixture( - fixtures.FakeLogger( - format=_LOG_FORMAT, - level=level, - nuke_handlers=capture_logs, - ) - ) - else: - logging.basicConfig(format=_LOG_FORMAT, level=level) - - def create_tempfiles(self, files, ext='.conf'): - tempfiles = [] - for (basename, contents) in files: - if not os.path.isabs(basename): - (fd, path) = tempfile.mkstemp(prefix=basename, suffix=ext) - else: - path = basename + ext - fd = os.open(path, os.O_CREAT | os.O_WRONLY) - tempfiles.append(path) - try: - os.write(fd, contents) - finally: - os.close(fd) - return tempfiles diff --git a/graffiti/openstack/common/timeutils.py b/graffiti/openstack/common/timeutils.py deleted file mode 100644 index 52688a0..0000000 --- a/graffiti/openstack/common/timeutils.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# 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. - -""" -Time related utilities and helper functions. -""" - -import calendar -import datetime -import time - -import iso8601 -import six - - -# ISO 8601 extended time format with microseconds -_ISO8601_TIME_FORMAT_SUBSECOND = '%Y-%m-%dT%H:%M:%S.%f' -_ISO8601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S' -PERFECT_TIME_FORMAT = _ISO8601_TIME_FORMAT_SUBSECOND - - -def isotime(at=None, subsecond=False): - """Stringify time in ISO 8601 format.""" - if not at: - at = utcnow() - st = at.strftime(_ISO8601_TIME_FORMAT - if not subsecond - else _ISO8601_TIME_FORMAT_SUBSECOND) - tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' - st += ('Z' if tz == 'UTC' else tz) - return st - - -def parse_isotime(timestr): - """Parse time from ISO 8601 format.""" - try: - return iso8601.parse_date(timestr) - except iso8601.ParseError as e: - raise ValueError(six.text_type(e)) - except TypeError as e: - raise ValueError(six.text_type(e)) - - -def strtime(at=None, fmt=PERFECT_TIME_FORMAT): - """Returns formatted utcnow.""" - if not at: - at = utcnow() - return at.strftime(fmt) - - -def parse_strtime(timestr, fmt=PERFECT_TIME_FORMAT): - """Turn a formatted time back into a datetime.""" - return datetime.datetime.strptime(timestr, fmt) - - -def normalize_time(timestamp): - """Normalize time in arbitrary timezone to UTC naive object.""" - offset = timestamp.utcoffset() - if offset is None: - return timestamp - return timestamp.replace(tzinfo=None) - offset - - -def is_older_than(before, seconds): - """Return True if before is older than seconds.""" - if isinstance(before, six.string_types): - before = parse_strtime(before).replace(tzinfo=None) - else: - before = before.replace(tzinfo=None) - - return utcnow() - before > datetime.timedelta(seconds=seconds) - - -def is_newer_than(after, seconds): - """Return True if after is newer than seconds.""" - if isinstance(after, six.string_types): - after = parse_strtime(after).replace(tzinfo=None) - else: - after = after.replace(tzinfo=None) - - return after - utcnow() > datetime.timedelta(seconds=seconds) - - -def utcnow_ts(): - """Timestamp version of our utcnow function.""" - if utcnow.override_time is None: - # NOTE(kgriffs): This is several times faster - # than going through calendar.timegm(...) - return int(time.time()) - - return calendar.timegm(utcnow().timetuple()) - - -def utcnow(): - """Overridable version of utils.utcnow.""" - if utcnow.override_time: - try: - return utcnow.override_time.pop(0) - except AttributeError: - return utcnow.override_time - return datetime.datetime.utcnow() - - -def iso8601_from_timestamp(timestamp): - """Returns a iso8601 formatted date from timestamp.""" - return isotime(datetime.datetime.utcfromtimestamp(timestamp)) - - -utcnow.override_time = None - - -def set_time_override(override_time=None): - """Overrides utils.utcnow. - - Make it return a constant time or a list thereof, one at a time. - - :param override_time: datetime instance or list thereof. If not - given, defaults to the current UTC time. - """ - utcnow.override_time = override_time or datetime.datetime.utcnow() - - -def advance_time_delta(timedelta): - """Advance overridden time using a datetime.timedelta.""" - assert(not utcnow.override_time is None) - try: - for dt in utcnow.override_time: - dt += timedelta - except TypeError: - utcnow.override_time += timedelta - - -def advance_time_seconds(seconds): - """Advance overridden time by seconds.""" - advance_time_delta(datetime.timedelta(0, seconds)) - - -def clear_time_override(): - """Remove the overridden time.""" - utcnow.override_time = None - - -def marshall_now(now=None): - """Make an rpc-safe datetime with microseconds. - - Note: tzinfo is stripped, but not required for relative times. - """ - if not now: - now = utcnow() - return dict(day=now.day, month=now.month, year=now.year, hour=now.hour, - minute=now.minute, second=now.second, - microsecond=now.microsecond) - - -def unmarshall_time(tyme): - """Unmarshall a datetime dict.""" - return datetime.datetime(day=tyme['day'], - month=tyme['month'], - year=tyme['year'], - hour=tyme['hour'], - minute=tyme['minute'], - second=tyme['second'], - microsecond=tyme['microsecond']) - - -def delta_seconds(before, after): - """Return the difference between two timing objects. - - Compute the difference in seconds between two date, time, or - datetime objects (as a float, to microsecond resolution). - """ - delta = after - before - return total_seconds(delta) - - -def total_seconds(delta): - """Return the total seconds of datetime.timedelta object. - - Compute total seconds of datetime.timedelta, datetime.timedelta - doesn't have method total_seconds in Python2.6, calculate it manually. - """ - try: - return delta.total_seconds() - except AttributeError: - return ((delta.days * 24 * 3600) + delta.seconds + - float(delta.microseconds) / (10 ** 6)) - - -def is_soon(dt, window): - """Determines if time is going to happen in the next window seconds. - - :param dt: the time - :param window: minimum seconds to remain to consider the time not soon - - :return: True if expiration is within the given duration - """ - soon = (utcnow() + datetime.timedelta(seconds=window)) - return normalize_time(dt) <= soon diff --git a/graffiti/tests/__init__.py b/graffiti/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/tests/base.py b/graffiti/tests/base.py deleted file mode 100644 index 138a1ab..0000000 --- a/graffiti/tests/base.py +++ /dev/null @@ -1,283 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2010-2011 OpenStack Foundation -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# 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. - -import os - -import fixtures -from oslo.config import cfg -import pecan -import pecan.testing -import testtools - -from graffiti.db import api as db_api -from graffiti.openstack.common import lockutils -from graffiti.openstack.common import log as logging - - -cfg.set_defaults(lockutils.util_opts, lock_path='/tmp') - -CONF = cfg.CONF -_TRUE_VALUES = ('true', '1', 'yes') - -_DB_CACHE = None - -logging.setup('graffiti') - - -class TestCase(testtools.TestCase): - - """Test case base class for all unit tests.""" - - def setUp(self): - """Run before each test method to initialize test environment.""" - - super(TestCase, self).setUp() - test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0) - try: - test_timeout = int(test_timeout) - except ValueError: - # If timeout value is invalid do not set a timeout. - test_timeout = 0 - if test_timeout > 0: - self.useFixture(fixtures.Timeout(test_timeout, gentle=True)) - - self.useFixture(fixtures.NestedTempfile()) - self.useFixture(fixtures.TempHomeDir()) - - self.addCleanup(CONF.reset) - - if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES: - stdout = self.useFixture(fixtures.StringStream('stdout')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) - if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES: - stderr = self.useFixture(fixtures.StringStream('stderr')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) - - self.log_fixture = self.useFixture(fixtures.FakeLogger()) - - def config(self, **kw): - """Override some configuration values. - - The keyword arguments are the names of configuration options to - override and their values. - - If a group argument is supplied, the overrides are applied to - the specified configuration option group. - - All overrides are automatically cleared at the end of the current - test by the fixtures cleanup process. - """ - group = kw.pop('group', None) - for k, v in kw.iteritems(): - CONF.set_override(k, v, group) - - -class DbTestCase(TestCase): - - def setUp(self): - super(DbTestCase, self).setUp() - self.setup_db() - - def setup_db(self): - CONF.set_default('connection', "sqlite://", group='database') - db_api.setup_db() - self.addCleanup(self._drop_db) - - def _drop_db(self): - db_api.drop_db() - db_api.cleanup() - - -PATH_PREFIX = '/v1' - - -class FunctionalTest(DbTestCase): - """Used for functional tests of Pecan controllers where you need to - test your literal application and its integration with the - framework. - """ - - def setUp(self): - super(FunctionalTest, self).setUp() - - self.disable_auth_checks() - self.addCleanup(self._reset_checks) - - self.app = self._make_app() - self.addCleanup(self._reset_pecan) - - def _make_app(self): - config = { - 'app': { - 'root': 'graffiti.api.root_controller.RootController', - 'modules': ['graffiti.api'] - } - } - return pecan.testing.load_test_app(config=config) - - def _reset_pecan(self): - pecan.set_config({}, overwrite=True) - - def _request_json(self, path, params, expect_errors=False, headers=None, - method="post", extra_environ=None, status=None, - path_prefix=PATH_PREFIX): - """Sends simulated HTTP request to Pecan test app. - - :param path: url path of target service - :param params: content for wsgi.input of request - :param expect_errors: Boolean value; whether an error is expected based - on request - :param headers: a dictionary of headers to send along with the request - :param method: Request method type. Appropriate method function call - should be used rather than passing attribute in. - :param extra_environ: a dictionary of environ variables to send along - with the request - :param status: expected status code of response - :param path_prefix: prefix of the url path - """ - full_path = path_prefix + path - response = getattr(self.app, "%s_json" % method)( - str(full_path), - params=params, - headers=headers, - status=status, - extra_environ=extra_environ, - expect_errors=expect_errors - ) - return response - - def put_json(self, path, params, expect_errors=False, headers=None, - extra_environ=None, status=None): - """Sends simulated HTTP PUT request to Pecan test app. - - :param path: url path of target service - :param params: content for wsgi.input of request - :param expect_errors: Boolean value; whether an error is expected based - on request - :param headers: a dictionary of headers to send along with the request - :param extra_environ: a dictionary of environ variables to send along - with the request - :param status: expected status code of response - """ - return self._request_json(path=path, params=params, - expect_errors=expect_errors, - headers=headers, extra_environ=extra_environ, - status=status, method="put") - - def post_json(self, path, params, expect_errors=False, headers=None, - extra_environ=None, status=None): - """Sends simulated HTTP POST request to Pecan test app. - - :param path: url path of target service - :param params: content for wsgi.input of request - :param expect_errors: Boolean value; whether an error is expected based - on request - :param headers: a dictionary of headers to send along with the request - :param extra_environ: a dictionary of environ variables to send along - with the request - :param status: expected status code of response - """ - return self._request_json(path=path, params=params, - expect_errors=expect_errors, - headers=headers, extra_environ=extra_environ, - status=status, method="post") - - def patch_json(self, path, params, expect_errors=False, headers=None, - extra_environ=None, status=None): - """Sends simulated HTTP PATCH request to Pecan test app. - - :param path: url path of target service - :param params: content for wsgi.input of request - :param expect_errors: Boolean value; whether an error is expected based - on request - :param headers: a dictionary of headers to send along with the request - :param extra_environ: a dictionary of environ variables to send along - with the request - :param status: expected status code of response - """ - return self._request_json(path=path, params=params, - expect_errors=expect_errors, - headers=headers, extra_environ=extra_environ, - status=status, method="patch") - - def delete(self, path, expect_errors=False, headers=None, - extra_environ=None, status=None, path_prefix=PATH_PREFIX): - """Sends simulated HTTP DELETE request to Pecan test app. - - :param path: url path of target service - :param expect_errors: Boolean value; whether an error is expected based - on request - :param headers: a dictionary of headers to send along with the request - :param extra_environ: a dictionary of environ variables to send along - with the request - :param status: expected status code of response - :param path_prefix: prefix of the url path - """ - full_path = path_prefix + path - response = self.app.delete(str(full_path), - headers=headers, - status=status, - extra_environ=extra_environ, - expect_errors=expect_errors) - return response - - def get_json(self, path, expect_errors=False, headers=None, - extra_environ=None, q=[], path_prefix=PATH_PREFIX, **params): - """Sends simulated HTTP GET request to Pecan test app. - - :param path: url path of target service - :param expect_errors: Boolean value;whether an error is expected based - on request - :param headers: a dictionary of headers to send along with the request - :param extra_environ: a dictionary of environ variables to send along - with the request - :param q: list of queries consisting of: field, value, op, and type - keys - :param path_prefix: prefix of the url path - :param params: content for wsgi.input of request - """ - full_path = path_prefix + path - query_params = {'q.field': [], - 'q.value': [], - 'q.op': [], - } - for query in q: - for name in ['field', 'op', 'value']: - query_params['q.%s' % name].append(query.get(name, '')) - all_params = {} - all_params.update(params) - if q: - all_params.update(query_params) - response = self.app.get(full_path, - params=all_params, - headers=headers, - extra_environ=extra_environ, - expect_errors=expect_errors) - if not expect_errors: - response = response.json - return response - - def validate_link(self, link): - """Checks if the given link can get correct data.""" - - # removes 'http://loicalhost' part - full_path = link.split('localhost', 1)[1] - try: - self.get_json(full_path, path_prefix='') - return True - except Exception: - return False diff --git a/graffiti/tests/db/__init__.py b/graffiti/tests/db/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/tests/db/test_db_api.py b/graffiti/tests/db/test_db_api.py deleted file mode 100644 index 2a1414d..0000000 --- a/graffiti/tests/db/test_db_api.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright (c) 2014 Mirantis Inc. -# -# 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.base.py - -from graffiti.db import api as db_api -from graffiti.tests import base - - -class BaseDbTestCase(base.DbTestCase): - def setUp(self): - super(BaseDbTestCase, self).setUp() - - def _assert_saved_fields(self, expected, actual): - for k in expected.keys(): - self.assertEqual(expected[k], actual[k]) - - def _test_create(self, ref, save_method): - saved = save_method(ref) - - self.assertIsNotNone(saved.name) - self._assert_saved_fields(ref, saved) - - def _test_update_by_name(self, ref, delta, create, update): - saved = create(ref) - updated = update(saved.name, delta) - - self.assertEqual(saved.name, updated.name) - self._assert_saved_fields(delta, updated) - - def _test_update_by_named_namespace(self, ref, delta, create, update): - saved = create(ref) - updated = update(saved.name, saved.namespace, delta) - - self.assertEqual(saved.name, updated.name) - self.assertEqual(saved.namespace, updated.namespace) - self._assert_saved_fields(delta, updated) - - -class NamespaceTest(BaseDbTestCase): - - def setUp(self): - super(NamespaceTest, self).setUp() - - self.namespace_01 = { - 'name': u'OS:Glance', - 'scope': u'cloud', - 'owner': u'an-owner' - } - - self.capability_type_rel = { - 'name': u'MySQL', - 'namespace': u'OS:Glance', - 'description': u'MySQL Capability Type description' - } - - def test_create_namespace(self): - self._test_create(self.namespace_01, db_api.namespace_create) - - def test_update_namespace(self): - delta = { - 'scope': u'New Scope', - 'owner': u'New Owner' - } - self._test_update_by_name(self.namespace_01, delta, - db_api.namespace_create, - db_api.namespace_update) - - def test_delete_namespace(self): - created = db_api.namespace_create(self.namespace_01) - self.assertIsNotNone(created, "Could not create a Namespace.") - db_api.namespace_delete(created.name) - retrieved = db_api.namespace_get(created.name) - self.assertIsNone(retrieved, "Created Namespace not deleted.") - - def test_cascade_delete_namespace(self): - # Test deletion of namespace, cascade deletes related capability_types - created_ns = db_api.namespace_create(self.namespace_01) - self.assertIsNotNone(created_ns, "Could not create a Namespace.") - - # Assuming capability_type_##.namespace == namespace.name - ct_01 = db_api.capability_type_create(self.capability_type_rel) - self.assertIsNotNone( - ct_01, "Could not create related capability_type") - - db_api.namespace_delete(created_ns.name) - - retrieved = db_api.namespace_get(created_ns.name) - self.assertIsNone(retrieved, "Created Namespace not deleted.") - - retrieved = db_api.capability_type_get(ct_01.name, ct_01.namespace) - self.assertIsNone( - retrieved, "Associated Capability_Type not deleted.") - - -class CapabilityTypeTest(BaseDbTestCase): - - def setUp(self): - super(CapabilityTypeTest, self).setUp() - - self.capability_type_01 = { - 'name': u'MySQL', - 'namespace': u'OS:Glance', - 'description': u'MySQL Capability Type description' - } - - self.capability_type_02 = { - 'name': u'Apache2', - 'namespace': u'OS:Glance', - 'description': u'Apache2 Capability Type description' - } - - def test_create_capability_type(self): - self._test_create(self.capability_type_01, - db_api.capability_type_create) - - def test_update_capability_type(self): - delta = { - 'description': u'New Description' - } - self._test_update_by_named_namespace(self.capability_type_01, delta, - db_api.capability_type_create, - db_api.capability_type_update) - - def test_delete_capability_type(self): - created = db_api.capability_type_create(self.capability_type_01) - self.assertIsNotNone(created, "Could not create a capability_type.") - db_api.capability_type_delete(created.name, created.namespace) - retrieved = db_api.capability_type_get(created.name, created.namespace) - self.assertIsNone(retrieved, "Created capability_type not deleted.") diff --git a/graffiti/tests/drivers/__init__.py b/graffiti/tests/drivers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/graffiti/tests/drivers/test_db_resource_driver.py b/graffiti/tests/drivers/test_db_resource_driver.py deleted file mode 100644 index 0105955..0000000 --- a/graffiti/tests/drivers/test_db_resource_driver.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -from graffiti.api.tests import pecan_base -from graffiti.common import driver_factory -from graffiti.drivers import base as driver_base - - -class TestLocalResourceDriver(pecan_base.TestCase): - - def setUp(self): - super(TestLocalResourceDriver, self).setUp() - self.driver = driver_factory.get_driver("GFT::Local") - - def test_driver_interfaces(self): - self.assertIsInstance( - self.driver.resource, - driver_base.ResourceInterface - ) diff --git a/graffiti/tests/drivers/test_glance_resource_driver.py b/graffiti/tests/drivers/test_glance_resource_driver.py deleted file mode 100644 index 4f1b65b..0000000 --- a/graffiti/tests/drivers/test_glance_resource_driver.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - - -from graffiti.api.tests import pecan_base -from graffiti.common import driver_factory -from graffiti.drivers import base as driver_base - - -class TestGlanceResourceDriver(pecan_base.TestCase): - - def setUp(self): - super(TestGlanceResourceDriver, self).setUp() - self.driver = driver_factory.get_driver("OS::Glance::Image") - - def test_driver_interfaces(self): - self.assertIsInstance( - self.driver.resource, - driver_base.ResourceInterface - ) diff --git a/graffiti/tests/tools/mock_glance_image.py b/graffiti/tests/tools/mock_glance_image.py deleted file mode 100644 index f2c02d2..0000000 --- a/graffiti/tests/tools/mock_glance_image.py +++ /dev/null @@ -1,319 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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. - -from datetime import datetime -from glanceclient import Client as glance_client -from os import environ as env -import random -import uuid - -import keystoneclient.v2_0.client as keystone_client - - -class MockGlanceImage(object): - - IMAGE_OS_DISTROS = ['arch', 'centos', 'debian', 'fedora', 'freebsd', - 'gentoo', 'netbsd', 'openbsd', 'opensuse', 'rhel', - 'sled', 'ubuntu', 'windows'] - # TODO(wko): Find Versions - # 'mandrake', 'mandriva', 'mes', 'msdos', 'netware', - # 'opensolaris', - - ARCH_VERSIONS = ['rolling'] - - CENTOS_VERSIONS = ['5.1', '5.2', '5.3', '5.5', '5.6', '6.0', '6.1', - '6.2', '6.3', '6.4', '6.5'] - - DEBIAN_VERSIONS = ['5', '6', '7'] - - FEDORA_VERSIONS = ['17', '18', '19', '20'] - - FREEBSD_VERSIONS = ['7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', - '8.2', '8.3', '8.4', '9.0', '9.1', '9.2', '10.0'] - - GENTOO_VERSIONS = ['rolling'] - - NETBSD_VERSIONS = ['4.0', '5.0', '6.0', '6.1'] - - OPENSUSE_VERSIONS = ['11.1', '11.2', '11.3', '11.4', '12.1', - '12.2', '12.3', '13.1'] - - OPENBSD_VERSIONS = ['4.0', '4.1', '4.2', '4.3', '4.4', '4.5', '4.6', - '4.7', '4.8', '4.9', '5.0', '5.1', '5.2', '5.3', - '5.4'] - - SLED_VERSIONS = ['11 sp1', '11 sp2', '11 sp3'] - - RHEL_VERSIONS = ['5.1', '5.2', '5.3', '5.5', '5.6', '6.0', '6.1', - '6.2', '6.3', '6.4', '6.5'] - - UBUNTU_VERSIONS = ['10.04 LTS', '10.04.1 LTS', '10.04.2 LTS', - '10.04.3 LTS', '10.04.4 LTS', '12.04 LTS', - '12.04.1 LTS', '12.04.2 LTS', '12.04.3 LTS', - '12.04.4 LTS', '12.10', '13.10'] - - WINDOWS_VERSIONS = ['Windows Server 2008', 'Windows Server 2008 R2', - 'Windows Server 2012', 'Windows Server 2012 R2'] - - # Image Filter Properties: - # vm_mode - # hypervisor_type - # architecture - # TODO(wko): correlate valid values based on "other" property values - # e.g., - VM_MODES = ['hvm', 'xen', 'uml', 'exe'] - - HYPERVISOR_TYPES = ['xem', 'qemu', 'kvm', 'lxc', 'uml', 'vmware', 'hyperv'] - - IMAGE_ARCHITECTURES = ['i686', 'x86_64'] - - # TODO(wko): figure out when these would be appropriate(by os_distro?) - # IMAGE_ARCHITECTURES = ['alpha', 'armv71', 'cris', 'i686', 'lm32', - # 'm68k', 'microblaze', 'microblazeel', 'mips', - # 'mipsel', 'mips64', 'mips64el', 'openrisc', - # 'parisc', 'parisc64', 'ppc', 'ppc64', - # 'ppcemb', 's390', 's390x', 'sh4', 'sh4eb', - # 'sparc', 'sparc64', 'unicore32', 'x86_64', - # 'xtensa', 'xtensaeb'] - - IMAGE_OS_TYPES = ['linux', 'windows'] - - # Image Properties: - # instance_uuid = uuid of guest instance used to create a snapshot image - # kernel_id = ID of Glance AMI style image used as kernel when booting. - # ramdisk_id = ID of Glance image to use as ramdisk during image boot - - # Image Snapshot Properties: - # instance_uuid = (see Image Properties) - # image_location = snapshot - # image_type = snapshot - # base_image_ref = uuid of the glance image the snapshot was taken on - ''' - Properties added during horizon snapshot processing: - -------------------------------------+------------------------------------ - Property 'base_image_ref' |979c2c87-852b-48a2-9dcf-46e133ef0f47 - Property 'image_location' |snapshot - Property 'image_state' |available - Property 'image_type' |snapshot - Property 'instance_type_ephemeral_gb'|0 - Property 'instance_type_flavorid' |1 - Property 'instance_type_id' |2 - Property 'instance_type_memory_mb' |512 - Property 'instance_type_name' |m1.tiny - Property 'instance_type_root_gb' |1 - Property 'instance_type_rxtx_factor' |1.0 - Property 'instance_type_swap' |0 - Property 'instance_type_vcpus' |1 - Property 'instance_uuid' |660bf546-382f-4394-8ba8-1188889d88f9 - Property 'network_allocated' |True - Property 'owner_id' |0e5831d3a5cb4469bfb29cc69c8760a8 - Property 'user_id' |bb52b834b45d41599bc69cde3be57bd7 - ''' - - COMPUTE_DRIVERS = ['VMWareComputeDriver', 'XenComputeDriver', - 'libvirtDriver'] - # VMWareComputeDriver properties: - # vmware_adaptertype - # vmware_ostype - # vmware_image_version - # TODO(wko): determine valid vmware value combinations: - # http://docs.openstack.org/trunk/config-reference/content/vmware.html - # - # XenComputeDriver properties: - # auto_disk_config = true/false - # os_type = linux/windows - # - # libvirtDriver properties: - # hw_video_model - HW_VIDEO_MODELS = ['vga', 'cirrus', 'vmvga', 'xen', 'gxl'] - - def __init__(self, glance_endpoint=None, auth_token=None, - image_name_prefix='mock-image', - image_file='/var/tmp/mock-test.iso'): - - self.glance_endpoint = glance_endpoint - self.auth_token = auth_token - if glance_endpoint is None or auth_token is None: - keystone = keystone_client.Client( - auth_url=env['OS_AUTH_URL'], - username=env['OS_USERNAME'], - password=env['OS_PASSWORD'], - tenant_name=env['OS_TENANT_NAME']) - - if glance_endpoint is None: - self.glance_endpoint = keystone.service_catalog.url_for( - service_type='image') - - if auth_token is None: - self.auth_token = keystone.auth_token - - self.glance = glance_client('1', endpoint=self.glance_endpoint, - token=self.auth_token) - - self.image_name_prefix = image_name_prefix - self.image_file = image_file - - def _get_image_distro(self): - return random.choice(self.IMAGE_OS_DISTROS) - - def _get_os_version(self, os_distro): - # - os_version = '' - if os_distro == 'arch': - os_version = random.choice(self.ARCH_VERSIONS) - elif os_distro == 'centos': - os_version = random.choice(self.CENTOS_VERSIONS) - elif os_distro == 'debian': - os_version = random.choice(self.DEBIAN_VERSIONS) - elif os_distro == 'fedora': - os_version = random.choice(self.FEDORA_VERSIONS) - elif os_distro == 'freebsd': - os_version = random.choice(self.FREEBSD_VERSIONS) - elif os_distro == 'gentoo': - os_version = random.choice(self.GENTOO_VERSIONS) - elif os_distro == 'netbsd': - os_version = random.choice(self.NETBSD_VERSIONS) - elif os_distro == 'openbsd': - os_version = random.choice(self.OPENBSD_VERSIONS) - elif os_distro == 'opensuse': - os_version = random.choice(self.OPENSUSE_VERSIONS) - elif os_distro == 'rhel': - os_version = random.choice(self.RHEL_VERSIONS) - elif os_distro == 'sled': - os_version = random.choice(self.SLED_VERSIONS) - elif os_distro == 'ubuntu': - os_version = random.choice(self.UBUNTU_VERSIONS) - elif os_distro == 'windows': - os_version = random.choice(self.WINDOWS_VERSIONS) - - return os_version - - def _get_os_type(self, os_distro): - os_type = 'linux' - if os_distro == 'windows': - os_type = 'windows' - return os_type - - def _get_image_architecture(self): - return random.choice(self.IMAGE_ARCHITECTURES) - - def _get_compute_driver_properties(self): - compute_driver = random.choice(self.COMPUTE_DRIVERS) - properties = {} - if compute_driver.lower() == 'vmwarecomputedriver': - properties['vmware_adaptertype'] = 'ide' - properties['vmware_disktype'] = 'sparse' - properties['vmware_ostype'] = 'ubuntu64Guest' - properties['vmware_image_version'] = '1' - elif compute_driver.lower() == 'xencomputedriver': - properties['auto_disk_config'] = 'false' - # properties['os_type'] = self._get_os_type(os_distro) - elif compute_driver.lower() == 'libvirtdriver': - properties['hw_video_model'] = random.choice(self.HW_VIDEO_MODELS) - - return properties - - def _get_base_properties(self): - properties = {} - os_distro = self._get_image_distro() - properties['os_distro'] = os_distro - properties['os_version'] = self._get_os_version(os_distro) - properties['architecture'] = self._get_image_architecture() - properties['os_type'] = self._get_os_type(os_distro) - properties['vm_mode'] = random.choice(self.VM_MODES) - properties['hypervisor_type'] = random.choice(self.HYPERVISOR_TYPES) - properties = dict(properties.items() + - self._get_compute_driver_properties().items()) - - return properties - - def _get_snapshot_properties(self, base_image_ref, owner): - properties = self._get_base_properties() - properties['image_type'] = 'snapshot' - properties['image_location'] = 'snapshot' - properties['instance_uuid'] = uuid.uuid4() - properties['base_image_ref'] = base_image_ref - - # Additional Properties added during horizon snapshot - # TODO(wko): account for these in the GLANCE namespace? - properties['instance_type_ephemeral_gb'] = '0' - properties['instance_type_flavorid'] = '2' - properties['instance_type_id'] = '5' - properties['instance_type_memory_mb'] = '2048' - properties['instance_type_name'] = 'm1.small' - properties['instance_type_root_gb'] = '20' - properties['instance_type_rxtx_factor'] = '1.0' - properties['instance_type_swap'] = '0' - properties['instance_type_vcpus'] = '1' - properties['network_allocated'] = 'True' - properties['owner_id'] = owner - properties['user_id'] = str(uuid.uuid4().hex) - - return properties - - def _get_image_name(self): - tm = datetime.now() - stamp = '-%s%s%s.%s.%s' %\ - (tm.year, "{0:0>2}".format(tm.month), - "{0:0>2}".format(tm.day), - (tm.hour * 3600) + (tm.minute * 60) + tm.second, - tm.microsecond / 100) - - return self.image_name_prefix + stamp - - def _create_image(self, image_name): - image = self.glance.images.create(name=image_name) - image.update(disk_format='vmdk', container_format='bare') - image.update(data=open(self.image_file, 'rb')) - return image - - def _update_image(self, image, image_properties): - return image.update(properties=image_properties, purge_props=False) - - def create(self, num_base_images=1, num_snapshots_per_base=0, - dry_run=True): - # Create num_base_images with num_snapshots_per_base - # if num_base_images is <= 0 no snapshot images will be created. - count = 0 - while count < num_base_images: - base_image_name = self._get_image_name() - print('base_image_name = %s' % base_image_name) - print('base_properties = %s' % self._get_base_properties()) - print('snapshot_properties = %s' % self._get_snapshot_properties( - 'not-base-ref-yet', 'no-owner-yet')) - if dry_run is False: - image = self._create_image(base_image_name) - self._update_image(image, self._get_base_properties()) - base_image_ref = image.id - snapshot_properties = self._get_snapshot_properties( - base_image_ref, image.owner) - snap_count = 1 - while snap_count <= num_snapshots_per_base: - snap_image_name =\ - base_image_name + "-snap-{0:0>3}".format(snap_count) - image = self._create_image(snap_image_name) - self._update_image(image, snapshot_properties) - snap_count += 1 - count += 1 - - -# with open('/tmp/authtoken') as fp: -# authtoken = fp.readline() - -# Supply glance endpoint URL and authtoken or if not passed to -# MockGlanceImage() then these env variables must be set: -# OS_TENANT_NAME, OS_AUTH_URL, OS_USERNAME and OS_PASSWORD -test = MockGlanceImage() -test.create(num_base_images=1, num_snapshots_per_base=2, dry_run=False) diff --git a/openstack-common.conf b/openstack-common.conf deleted file mode 100644 index 4d58a2e..0000000 --- a/openstack-common.conf +++ /dev/null @@ -1,6 +0,0 @@ -[DEFAULT] - -# The list of modules to copy from oslo-incubator.git - -# The base module to hold the copy of openstack.common -base=graffiti \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 65d92bb..0000000 --- a/requirements.txt +++ /dev/null @@ -1,15 +0,0 @@ -pbr>=0.5.21,<1.0 -Babel>=0.9.6 -pecan>=0.4.4 -WSME>=0.6 -oslo.config>=1.2.0 -python-glanceclient -python-novaclient -python-cinderclient -httplib2>=0.7.5 -alembic>=0.4.1 -iso8601>=0.1.8 -requests>=1.1 -six>=1.5.2 -SQLAlchemy>=0.8,<=0.8.99 -stevedore>=0.14 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 897cdaa..0000000 --- a/setup.cfg +++ /dev/null @@ -1,53 +0,0 @@ -[metadata] -name = graffiti -summary = Cloud Capability Service -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://www.openstack.org/ -classifier = - Environment :: OpenStack - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 2.6 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.3 - -[files] -packages = - graffiti - -[entry_points] -graffiti.drivers = - local = graffiti.drivers.local:LocalResourceDriver - glance = graffiti.drivers.glance:GlanceResourceDriver - nova = graffiti.drivers.nova:NovaResourceDriver - cinder = graffiti.drivers.cinder:CinderResourceDriver - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 - -[upload_sphinx] -upload-dir = doc/build/html - -[compile_catalog] -directory = graffiti/locale -domain = graffiti - -[update_catalog] -domain = graffiti -output_dir = graffiti/locale -input_file = graffiti/locale/graffiti.pot - -[extract_messages] -keywords = _ gettext ngettext l_ lazy_gettext -mapping_file = babel.cfg -output_file = graffiti/locale/graffiti.pot diff --git a/setup.py b/setup.py deleted file mode 100755 index 2a0786a..0000000 --- a/setup.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# 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. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -setuptools.setup( - setup_requires=['pbr>=0.5.21,<1.0'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 6e05591..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,15 +0,0 @@ -hacking>=0.5.6,<0.8 - -coverage>=3.6 -discover -fixtures>=0.3.14 -python-subunit -sphinx>=1.1.2 -oslo.sphinx -testrepository>=0.0.17 -testscenarios>=0.4,<0.5 -testtools>=0.9.32 - -posix_ipc>=0.9.8 -MySQL-python -psycopg2 diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 9a82bc7..0000000 --- a/tox.ini +++ /dev/null @@ -1,31 +0,0 @@ -[tox] -minversion = 1.6 -envlist = py27,py26,pep8 -skipsdist = True - -[testenv] -usedevelop = True -install_command = pip install -U {opts} {packages} -setenv = - VIRTUAL_ENV={envdir} -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = python setup.py testr --slowest --testr-args='{posargs}' - -[testenv:pep8] -commands = flake8 - -[testenv:venv] -commands = {posargs} - -[testenv:cover] -commands = python setup.py testr --coverage --testr-args='{posargs}' - -[flake8] -# H803 skipped on purpose per list discussion. -# E123, E125 skipped as they are invalid PEP-8. - -show-source = True -ignore = E123,E125,H803 -builtins = _ -exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build