From ce8599cf34a33539f5671d2686672ca118440560 Mon Sep 17 00:00:00 2001 From: Ghanshyam Mann Date: Fri, 27 Nov 2020 21:02:56 -0600 Subject: [PATCH] Retire the qinling-dashboard project As announced in openstack-discuss ML[1], Qinling project is retiring in Wallaby cycle. This commit retires the qinling-dashboard repository as per process deinfed in project-guide[2]. Anyone would like to maintain it again, please revert back this commit and propose the re-adding it to governance. The community wishes to express our thanks and appreciation to all of those who have contributed to the qinling-dashboard project over the years. Depends-On: https://review.opendev.org/c/openstack/project-config/+/764520 Needed-By: https://review.opendev.org/c/openstack/governance/+/764523 [1] http://lists.openstack.org/pipermail/openstack-discuss/2020-November/018638.html [2] https://docs.openstack.org/project-team-guide/repository.html#retiring-a-repository Change-Id: Ib1953185ed61f237040a9e4e5e727fd5e2befdb8 --- .gitignore | 108 -- .zuul.yaml | 7 - CONTRIBUTING.rst | 17 - HACKING.rst | 4 - LICENSE | 201 ---- MANIFEST.in | 4 - README.rst | 22 +- babel-django.cfg | 3 - babel-djangojs.cfg | 2 - devstack/plugin.sh | 61 -- devstack/settings | 2 - doc/requirements.txt | 16 - doc/source/conf.py | 105 -- doc/source/configuration/index.rst | 10 - doc/source/contributor/contributing.rst | 30 - doc/source/contributor/devstack.rst | 13 - doc/source/contributor/index.rst | 9 - doc/source/index.rst | 18 - doc/source/install/index.rst | 76 -- manage.py | 23 - qinling_dashboard/__init__.py | 0 qinling_dashboard/api/__init__.py | 39 - qinling_dashboard/api/qinling.py | 184 ---- qinling_dashboard/conf/qinling_policy.json | 20 - qinling_dashboard/content/__init__.py | 0 .../content/executions/__init__.py | 0 qinling_dashboard/content/executions/forms.py | 134 --- qinling_dashboard/content/executions/panel.py | 22 - .../content/executions/tables.py | 172 ---- qinling_dashboard/content/executions/tabs.py | 49 - .../templates/executions/_create.html | 6 - .../templates/executions/_detail_logs.html | 2 - .../executions/_detail_overview.html | 57 -- .../executions/_execution_result.html | 3 - .../templates/executions/create.html | 7 - .../templates/executions/detail.html | 11 - qinling_dashboard/content/executions/urls.py | 25 - qinling_dashboard/content/executions/views.py | 107 -- .../content/functions/__init__.py | 0 qinling_dashboard/content/functions/forms.py | 455 --------- qinling_dashboard/content/functions/panel.py | 22 - qinling_dashboard/content/functions/tables.py | 291 ------ qinling_dashboard/content/functions/tabs.py | 83 -- .../templates/functions/_create_function.html | 7 - .../templates/functions/_create_version.html | 6 - .../functions/_detail_executions.html | 3 - .../templates/functions/_detail_overview.html | 58 -- .../functions/_detail_version_overview.html | 31 - .../templates/functions/_detail_versions.html | 3 - .../templates/functions/_update_function.html | 7 - .../templates/functions/create_function.html | 7 - .../templates/functions/create_version.html | 7 - .../functions/templates/functions/detail.html | 11 - .../templates/functions/detail_version.html | 11 - .../templates/functions/update_function.html | 7 - qinling_dashboard/content/functions/urls.py | 42 - qinling_dashboard/content/functions/views.py | 309 ------ .../content/runtimes/__init__.py | 0 qinling_dashboard/content/runtimes/forms.py | 88 -- qinling_dashboard/content/runtimes/panel.py | 22 - qinling_dashboard/content/runtimes/tables.py | 92 -- qinling_dashboard/content/runtimes/tabs.py | 37 - .../runtimes/templates/runtimes/_create.html | 6 - .../templates/runtimes/_detail_overview.html | 38 - .../runtimes/templates/runtimes/create.html | 7 - .../runtimes/templates/runtimes/detail.html | 11 - qinling_dashboard/content/runtimes/urls.py | 22 - qinling_dashboard/content/runtimes/views.py | 94 -- .../_7110_project_function_engine_panel.py | 30 - .../enabled/_7120_project_runtimes_panel.py | 24 - .../enabled/_7130_project_functions_panel.py | 24 - .../enabled/_7140_project_executions_panel.py | 24 - qinling_dashboard/enabled/__init__.py | 0 qinling_dashboard/exceptions.py | 28 - .../locale/en_GB/LC_MESSAGES/django.po | 462 --------- .../locale/ko_KR/LC_MESSAGES/django.po | 466 --------- qinling_dashboard/test/__init__.py | 0 qinling_dashboard/test/helpers.py | 412 -------- qinling_dashboard/test/settings.py | 39 - qinling_dashboard/test/test_data/__init__.py | 0 .../test/test_data/exceptions.py | 51 - .../test/test_data/keystone_data.py | 339 ------- .../test/test_data/qinling_data.py | 104 -- qinling_dashboard/test/test_data/utils.py | 122 --- qinling_dashboard/test/tests/__init__.py | 0 qinling_dashboard/test/tests/api/__init__.py | 0 .../test/tests/api/test_qinling.py | 272 ----- .../test/tests/content/__init__.py | 0 .../test/tests/content/test_executions.py | 329 ------ .../test/tests/content/test_functions.py | 959 ------------------ .../test/tests/content/test_runtimes.py | 157 --- .../test/tests/test_validators.py | 293 ------ qinling_dashboard/utils.py | 79 -- qinling_dashboard/validators.py | 77 -- releasenotes/notes/.placeholder | 0 .../notes/drop-py-2-7-83f8eb457524a5e1.yaml | 6 - releasenotes/source/_static/.placeholder | 0 releasenotes/source/_templates/.placeholder | 0 releasenotes/source/conf.py | 274 ----- releasenotes/source/index.rst | 9 - .../locale/de/LC_MESSAGES/releasenotes.po | 21 - .../locale/en_GB/LC_MESSAGES/releasenotes.po | 22 - .../locale/ko_KR/LC_MESSAGES/releasenotes.po | 22 - releasenotes/source/unreleased.rst | 5 - releasenotes/source/victoria.rst | 6 - requirements.txt | 15 - setup.cfg | 25 - setup.py | 20 - test-requirements.txt | 21 - tox.ini | 81 -- 110 files changed, 8 insertions(+), 8156 deletions(-) delete mode 100644 .gitignore delete mode 100644 .zuul.yaml delete mode 100644 CONTRIBUTING.rst delete mode 100644 HACKING.rst delete mode 100644 LICENSE delete mode 100644 MANIFEST.in delete mode 100644 babel-django.cfg delete mode 100644 babel-djangojs.cfg delete mode 100644 devstack/plugin.sh delete mode 100644 devstack/settings delete mode 100644 doc/requirements.txt delete mode 100755 doc/source/conf.py delete mode 100644 doc/source/configuration/index.rst delete mode 100644 doc/source/contributor/contributing.rst delete mode 100644 doc/source/contributor/devstack.rst delete mode 100644 doc/source/contributor/index.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/install/index.rst delete mode 100755 manage.py delete mode 100644 qinling_dashboard/__init__.py delete mode 100644 qinling_dashboard/api/__init__.py delete mode 100644 qinling_dashboard/api/qinling.py delete mode 100644 qinling_dashboard/conf/qinling_policy.json delete mode 100644 qinling_dashboard/content/__init__.py delete mode 100644 qinling_dashboard/content/executions/__init__.py delete mode 100644 qinling_dashboard/content/executions/forms.py delete mode 100644 qinling_dashboard/content/executions/panel.py delete mode 100644 qinling_dashboard/content/executions/tables.py delete mode 100644 qinling_dashboard/content/executions/tabs.py delete mode 100644 qinling_dashboard/content/executions/templates/executions/_create.html delete mode 100644 qinling_dashboard/content/executions/templates/executions/_detail_logs.html delete mode 100644 qinling_dashboard/content/executions/templates/executions/_detail_overview.html delete mode 100644 qinling_dashboard/content/executions/templates/executions/_execution_result.html delete mode 100644 qinling_dashboard/content/executions/templates/executions/create.html delete mode 100644 qinling_dashboard/content/executions/templates/executions/detail.html delete mode 100644 qinling_dashboard/content/executions/urls.py delete mode 100644 qinling_dashboard/content/executions/views.py delete mode 100644 qinling_dashboard/content/functions/__init__.py delete mode 100644 qinling_dashboard/content/functions/forms.py delete mode 100644 qinling_dashboard/content/functions/panel.py delete mode 100644 qinling_dashboard/content/functions/tables.py delete mode 100644 qinling_dashboard/content/functions/tabs.py delete mode 100644 qinling_dashboard/content/functions/templates/functions/_create_function.html delete mode 100644 qinling_dashboard/content/functions/templates/functions/_create_version.html delete mode 100644 qinling_dashboard/content/functions/templates/functions/_detail_executions.html delete mode 100644 qinling_dashboard/content/functions/templates/functions/_detail_overview.html delete mode 100644 qinling_dashboard/content/functions/templates/functions/_detail_version_overview.html delete mode 100644 qinling_dashboard/content/functions/templates/functions/_detail_versions.html delete mode 100644 qinling_dashboard/content/functions/templates/functions/_update_function.html delete mode 100644 qinling_dashboard/content/functions/templates/functions/create_function.html delete mode 100644 qinling_dashboard/content/functions/templates/functions/create_version.html delete mode 100644 qinling_dashboard/content/functions/templates/functions/detail.html delete mode 100644 qinling_dashboard/content/functions/templates/functions/detail_version.html delete mode 100644 qinling_dashboard/content/functions/templates/functions/update_function.html delete mode 100644 qinling_dashboard/content/functions/urls.py delete mode 100644 qinling_dashboard/content/functions/views.py delete mode 100644 qinling_dashboard/content/runtimes/__init__.py delete mode 100644 qinling_dashboard/content/runtimes/forms.py delete mode 100644 qinling_dashboard/content/runtimes/panel.py delete mode 100644 qinling_dashboard/content/runtimes/tables.py delete mode 100644 qinling_dashboard/content/runtimes/tabs.py delete mode 100644 qinling_dashboard/content/runtimes/templates/runtimes/_create.html delete mode 100644 qinling_dashboard/content/runtimes/templates/runtimes/_detail_overview.html delete mode 100644 qinling_dashboard/content/runtimes/templates/runtimes/create.html delete mode 100644 qinling_dashboard/content/runtimes/templates/runtimes/detail.html delete mode 100644 qinling_dashboard/content/runtimes/urls.py delete mode 100644 qinling_dashboard/content/runtimes/views.py delete mode 100644 qinling_dashboard/enabled/_7110_project_function_engine_panel.py delete mode 100644 qinling_dashboard/enabled/_7120_project_runtimes_panel.py delete mode 100644 qinling_dashboard/enabled/_7130_project_functions_panel.py delete mode 100644 qinling_dashboard/enabled/_7140_project_executions_panel.py delete mode 100644 qinling_dashboard/enabled/__init__.py delete mode 100644 qinling_dashboard/exceptions.py delete mode 100644 qinling_dashboard/locale/en_GB/LC_MESSAGES/django.po delete mode 100644 qinling_dashboard/locale/ko_KR/LC_MESSAGES/django.po delete mode 100644 qinling_dashboard/test/__init__.py delete mode 100644 qinling_dashboard/test/helpers.py delete mode 100644 qinling_dashboard/test/settings.py delete mode 100644 qinling_dashboard/test/test_data/__init__.py delete mode 100644 qinling_dashboard/test/test_data/exceptions.py delete mode 100644 qinling_dashboard/test/test_data/keystone_data.py delete mode 100644 qinling_dashboard/test/test_data/qinling_data.py delete mode 100644 qinling_dashboard/test/test_data/utils.py delete mode 100644 qinling_dashboard/test/tests/__init__.py delete mode 100644 qinling_dashboard/test/tests/api/__init__.py delete mode 100644 qinling_dashboard/test/tests/api/test_qinling.py delete mode 100644 qinling_dashboard/test/tests/content/__init__.py delete mode 100644 qinling_dashboard/test/tests/content/test_executions.py delete mode 100644 qinling_dashboard/test/tests/content/test_functions.py delete mode 100644 qinling_dashboard/test/tests/content/test_runtimes.py delete mode 100644 qinling_dashboard/test/tests/test_validators.py delete mode 100644 qinling_dashboard/utils.py delete mode 100644 qinling_dashboard/validators.py delete mode 100644 releasenotes/notes/.placeholder delete mode 100644 releasenotes/notes/drop-py-2-7-83f8eb457524a5e1.yaml delete mode 100644 releasenotes/source/_static/.placeholder delete mode 100644 releasenotes/source/_templates/.placeholder delete mode 100644 releasenotes/source/conf.py delete mode 100644 releasenotes/source/index.rst delete mode 100644 releasenotes/source/locale/de/LC_MESSAGES/releasenotes.po delete mode 100644 releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po delete mode 100644 releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po delete mode 100644 releasenotes/source/unreleased.rst delete mode 100644 releasenotes/source/victoria.rst delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 test-requirements.txt delete mode 100644 tox.ini diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 389bd39..0000000 --- a/.gitignore +++ /dev/null @@ -1,108 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ - -# Editor specific settings -.idea/* -.vscode/* diff --git a/.zuul.yaml b/.zuul.yaml deleted file mode 100644 index 045efdb..0000000 --- a/.zuul.yaml +++ /dev/null @@ -1,7 +0,0 @@ -- project: - templates: - - check-requirements - - horizon-non-primary-django-jobs - - openstack-python3-victoria-jobs-horizon - - publish-openstack-docs-pti - - release-notes-jobs-python3 diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index d3b1c48..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,17 +0,0 @@ -If you would like to contribute to the development of OpenStack, you must -follow the steps in this page: - - https://docs.openstack.org/infra/manual/developers.html - -If you already have a good understanding of how the system works and your -OpenStack accounts are set up, you can skip to the development workflow -section of this documentation to learn how changes to OpenStack should be -submitted for review via the Gerrit tool: - - https://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on StoryBoard, not GitHub and Launchpad: - - https://storyboard.openstack.org/#!/project/1050 diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 1f5a6e4..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,4 +0,0 @@ -OpenStack Style Commandments -============================ - -Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +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. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 8ae66da..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -recursive-include qinling_dashboard *.html *.scss *.css *.js *.map *.svg *.png *.json - -include AUTHORS -include ChangeLog diff --git a/README.rst b/README.rst index 63aa712..86e34d6 100644 --- a/README.rst +++ b/README.rst @@ -1,16 +1,10 @@ -============================= -Welcome to Qinling Dashboard! -============================= +This project is no longer maintained. -Qinling dashboard is a horizon plugin for Qinling. +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". -* License: Apache license -* Documentation: https://docs.openstack.org/qinling-dashboard/latest/ -* Source: https://git.openstack.org/cgit/openstack/qinling-dashboard -* Bugs: https://bugs.launchpad.net/qinling-dashboard - -Team and repository tags ------------------------- - -.. image:: https://governance.openstack.org/tc/badges/qinling-dashboard.svg - :target: https://governance.openstack.org/tc/reference/tags/index.html +For any further questions, please email +openstack-discuss@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/babel-django.cfg b/babel-django.cfg deleted file mode 100644 index f5e7726..0000000 --- a/babel-django.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[python: **.py] -[django: **/templates/**.html] -[django: **/templates/**.csv] diff --git a/babel-djangojs.cfg b/babel-djangojs.cfg deleted file mode 100644 index b92caf6..0000000 --- a/babel-djangojs.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[javascript: **.js] -[angular: **/static/**.html] diff --git a/devstack/plugin.sh b/devstack/plugin.sh deleted file mode 100644 index b5eb5fe..0000000 --- a/devstack/plugin.sh +++ /dev/null @@ -1,61 +0,0 @@ -# plugin.sh - DevStack plugin.sh dispatch script qinling-dashboard - -QINLING_DASHBOARD_DIR=$(cd $(dirname $BASH_SOURCE)/.. && pwd) - -function install_qinling_dashboard { - # NOTE(shu-mutou): workaround for devstack bug: 1540328 - # where devstack install 'test-requirements' but should not do it - # for qinling-dashboard project as it installs Horizon from url. - # Remove following two 'mv' commands when mentioned bug is fixed. - mv $QINLING_DASHBOARD_DIR/test-requirements.txt $QINLING_DASHBOARD_DIR/_test-requirements.txt - - setup_develop ${QINLING_DASHBOARD_DIR} - - mv $QINLING_DASHBOARD_DIR/_test-requirements.txt $QINLING_DASHBOARD_DIR/test-requirements.txt -} - -function configure_qinling_dashboard { - cp -a ${QINLING_DASHBOARD_DIR}/qinling_dashboard/enabled/* ${DEST}/horizon/openstack_dashboard/local/enabled/ - cp -a ${QINLING_DASHBOARD_DIR}/qinling_dashboard/conf/qinling_policy.json ${DEST}/horizon/openstack_dashboard/conf/ - # NOTE: If locale directory does not exist, compilemessages will fail, - # so check for an existence of locale directory is required. - if [ -d ${QINLING_DASHBOARD_DIR}/qinling_dashboard/locale ]; then - (cd ${QINLING_DASHBOARD_DIR}/qinling_dashboard; DJANGO_SETTINGS_MODULE=openstack_dashboard.settings $PYTHON ../manage.py compilemessages) - fi -} - -# check for service enabled -if is_service_enabled qinling-dashboard; then - - if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then - # Set up system services - # no-op - : - - elif [[ "$1" == "stack" && "$2" == "install" ]]; then - # Perform installation of service source - echo_summary "Installing Qinling Dashboard" - install_qinling_dashboard - - elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then - # Configure after the other layer 1 and 2 services have been configured - echo_summary "Configuring Qinling Dashboard" - configure_qinling_dashboard - - elif [[ "$1" == "stack" && "$2" == "extra" ]]; then - # no-op - : - fi - - if [[ "$1" == "unstack" ]]; then - # no-op - : - fi - - if [[ "$1" == "clean" ]]; then - # Remove state and transient data - # Remember clean.sh first calls unstack.sh - # no-op - : - fi -fi diff --git a/devstack/settings b/devstack/settings deleted file mode 100644 index 0c27d47..0000000 --- a/devstack/settings +++ /dev/null @@ -1,2 +0,0 @@ -# settings file for qinling-dashboard plugin -enable_service qinling-dashboard diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index 617f948..0000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,16 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -# Order matters to the pip dependency resolver, so sorting this file -# changes how packages are installed. New dependencies should be -# added in alphabetical order, however, some dependencies may need to -# be installed in a specific order. -# -openstackdocstheme>=2.2.1 # Apache-2.0 -reno>=3.1.0 # Apache-2.0 -sphinx>=2.0.0,!=2.1.0 # BSD -sphinxcontrib-apidoc>=0.2.0 # BSD -sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD - -# NOTE: The following are required as horizon.test.settings loads it. -django-nose>=1.4.4 # BSD diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index e77e0ee..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,105 +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', - 'openstackdocstheme', - 'sphinxcontrib.rsvgconverter', - # 'sphinx.ext.intersphinx', -] - -# 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'Qinling Dashboard' -copyright = u'2017, OpenStack Developers' - -# openstackdocstheme options -openstackdocs_repo_name = 'openstack/qinling-dashboard' -openstackdocs_pdf_link = True -openstackdocs_auto_name = False -openstackdocs_use_storyboard = True - -# 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 = 'native' - -# -- 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'] -html_theme = 'openstackdocs' - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - -# -- Options for LaTeX output --------------------------------------------- - -# Disable usage of xindy https://bugzilla.redhat.com/show_bug.cgi?id=1643664 -latex_use_xindy = False - -latex_domain_indices = False - -latex_elements = { - 'makeindex': '', - 'printindex': '', - 'preamble': r'\setcounter{tocdepth}{3}', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -# NOTE: Specify toctree_only=True for a better document structure of -# the generated PDF file. -latex_documents = [ - ('index', - 'doc-qinling-dashboard.tex', - u'%s Documentation' % project, - u'OpenStack Developers', 'manual', True), -] - -man_pages = [ - ('index', u'Qinling Dashboard Documentation', - 'Documentation for Qinling Dashboard plugin to Openstack\ - Dashboard (Horizon)', - [u'OpenStack'], 1) -] - -# Example configuration for intersphinx: refer to the Python standard library. -# intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/source/configuration/index.rst b/doc/source/configuration/index.rst deleted file mode 100644 index 44f3008..0000000 --- a/doc/source/configuration/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -============= -Configuration -============= - -Qinling Dashboard currently has no configuration option. - -For more configurations, see -`Configuration Guide -`__ -in the Horizon documentation. diff --git a/doc/source/contributor/contributing.rst b/doc/source/contributor/contributing.rst deleted file mode 100644 index 852ccde..0000000 --- a/doc/source/contributor/contributing.rst +++ /dev/null @@ -1,30 +0,0 @@ -================= -How to Contribute -================= - -Contributor License Agreement ------------------------------ - -.. index:: - single: license; agreement - -In order to contribute to the Qinling Dashboard project, you need to have -signed OpenStack's contributor's agreement. - -.. seealso:: - - * https://docs.openstack.org/infra/manual/developers.html - * https://wiki.openstack.org/CLA - - -Project Hosting Details -------------------------- - -Bug tracker - https://storyboard.openstack.org/#!/project/1050 - -Code Hosting - https://git.openstack.org/cgit/openstack/qinling-dashboard - -Code Review - https://review.openstack.org/#/q/status:open+project:openstack/qinling-dashboard,n,z diff --git a/doc/source/contributor/devstack.rst b/doc/source/contributor/devstack.rst deleted file mode 100644 index 8127a25..0000000 --- a/doc/source/contributor/devstack.rst +++ /dev/null @@ -1,13 +0,0 @@ -================================= -Use Qinling Dashboard in DevStack -================================= - -Set up your ``local.conf`` to enable qinling-dashboard:: - - [[local|localrc]] - enable_plugin qinling-dashboard https://git.openstack.org/openstack/qinling-dashboard - - -.. note:: - - You also need to install Qinling itself into DevStack to use Qinling Dashboard. diff --git a/doc/source/contributor/index.rst b/doc/source/contributor/index.rst deleted file mode 100644 index 5eeb4b5..0000000 --- a/doc/source/contributor/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -========================= -Contributor Documentation -========================= - -.. toctree:: - :maxdepth: 2 - - contributing - devstack diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index de77276..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. openstack 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. - -.. the main title comes from README.rst - -.. include:: ../../README.rst - -Contents --------- - -.. toctree:: - :maxdepth: 2 - - Installation Guide - Configuration Guide - Contribution diff --git a/doc/source/install/index.rst b/doc/source/install/index.rst deleted file mode 100644 index 6985cd7..0000000 --- a/doc/source/install/index.rst +++ /dev/null @@ -1,76 +0,0 @@ -==================================== -Qinling Dashboard installation guide -==================================== - -This page describes the manual installation of qinling-dashboard, -while distribution packages may provide more automated process. - -.. note:: - - This page assumes horizon has been installed. - Horizon setup is beyond the scope of this page. - -Install Qinling Dashboard with all relevant packages to your Horizon environment. - -.. code-block:: console - - pip install qinling-dashboard - -In most cases, qinling-dashboard is installed into your python "site-packages" -directory like ``/usr/local/lib/python2.7/site-packages``. -We refer to the directory of qinling-dashboard as ```` below -and it would be ``/qinling_dashboard`` if installed via pip. -The path varies depending on Linux distribution you use. - -To enable qinling-dashboard plugin, you need to put horizon plugin setup files -into horizon "enabled" directory. - -The plugin setup files are found in ``/enabled``. - -.. code-block:: console - - $ cp /enabled/_[1-9]*.py \ - /usr/share/openstack-dashboard/openstack_dashboard/local/enabled - -.. note:: - - The directory ``local/enabled`` may be different depending on your - environment or distribution used. The path above is one used in Ubuntu - horizon package. - -Configure the policy file for qinling-dashboard in OpenStack Dashboard -``local_settings.py``. - -.. code-block:: python - - POLICY_FILES['function_engine'] = '/conf/qinling_policy.json' - -.. note:: - - If your ``local_settings.py`` has no ``POLICY_FILES`` yet, - you need to define the default ``POLICY_FILES`` in - ``local_settings.py``. If you use the example ``local_settings.py`` file - from horizon, what you need is to uncomment ``POLICY_FILES`` (which contains - the default values). - -Compile the translation message catalogs of qinling-dashboard. - -.. code-block:: console - - $ cd - $ python ./manage.py compilemessages - -Run the Django update commands. -Note that ``compress`` is required when you enable compression. - -.. code-block:: console - - $ cd - $ DJANGO_SETTINGS_MODULE=openstack_dashboard.settings python manage.py collectstatic --noinput - $ DJANGO_SETTINGS_MODULE=openstack_dashboard.settings python manage.py compress --force - -Finally, restart your web server. For example, in case of apache: - -.. code-block:: console - - $ sudo service apache2 restart diff --git a/manage.py b/manage.py deleted file mode 100755 index bf10ca6..0000000 --- a/manage.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -# 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 - -from django.core.management import execute_from_command_line - -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", - "qinling_dashboard.test.settings") - execute_from_command_line(sys.argv) diff --git a/qinling_dashboard/__init__.py b/qinling_dashboard/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qinling_dashboard/api/__init__.py b/qinling_dashboard/api/__init__.py deleted file mode 100644 index 7c529e5..0000000 --- a/qinling_dashboard/api/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2012 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# Copyright 2012 Nebula, Inc. -# Copyright 2013 Big Switch Networks -# -# 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. - -""" -Methods and interface objects used to interact with external APIs. - -API method calls return objects that are in many cases objects with -attributes that are direct maps to the data returned from the API http call. -Unfortunately, these objects are also often constructed dynamically, making -it difficult to know what data is available from the API object. Because of -this, all API calls should wrap their returned object in one defined here, -using only explicitly defined attributes and/or methods. - -In other words, Horizon developers not working on openstack_dashboard.api -shouldn't need to understand the finer details of APIs for -Keystone/Nova/Glance/Swift et. al. -""" -from qinling_dashboard.api import qinling - - -__all__ = [ - "qinling", -] diff --git a/qinling_dashboard/api/qinling.py b/qinling_dashboard/api/qinling.py deleted file mode 100644 index e5b727e..0000000 --- a/qinling_dashboard/api/qinling.py +++ /dev/null @@ -1,184 +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 json - -from django.conf import settings - -from horizon.utils.memoized import memoized - -from openstack_dashboard.api import base - -from openstack_dashboard.contrib.developer.profiler import api as profiler - -from qinlingclient import client as qinling_client - - -@memoized -def qinlingclient(request, password=None): - api_version = "1" - insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) - cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None) - endpoint = base.url_for(request, 'function-engine') - kwargs = { - 'token': request.user.token.id, - 'insecure': insecure, - 'ca_file': cacert, - 'username': request.user.username, - 'password': password - } - client = qinling_client.Client(api_version, endpoint, **kwargs) - return client - - -@profiler.trace -def runtimes_list(request): - return qinlingclient(request).runtimes.list() - - -@profiler.trace -def runtime_get(request, runtime_id): - return qinlingclient(request).runtimes.get(runtime_id) - - -def runtime_create(request, **params): - resource = qinlingclient(request).runtimes.create(**params) - return resource - - -def set_code(datum): - if isinstance(datum.code, str): - code_dict = json.loads(datum.code) - setattr(datum, "code", code_dict) - - -@profiler.trace -def functions_list(request, with_version=False): - functions = qinlingclient(request).functions.list() - for f in functions: - set_code(f) - - if with_version: - for f in functions: - function_id = f.id - my_versions = \ - qinlingclient(request).function_versions.list(function_id) - setattr(f, 'versions', my_versions) - return functions - - -@profiler.trace -def function_get(request, function_id): - function = qinlingclient(request).functions.get(function_id) - set_code(function) - return function - - -@profiler.trace -def function_create(request, **params): - resource = qinlingclient(request).functions.create(**params) - return resource - - -@profiler.trace -def function_update(request, function_id, **params): - resource = qinlingclient(request).functions.update(function_id, **params) - return resource - - -@profiler.trace -def function_delete(request, function_id): - qinlingclient(request).functions.delete(function_id) - - -@profiler.trace -def function_download(request, function_id): - function = qinlingclient(request).functions.get(function_id, - download=True) - return function - - -def set_result(datum): - if isinstance(datum.result, str): - result_dict = json.loads(datum.result) - setattr(datum, "result", result_dict) - - -@profiler.trace -def executions_list(request, function_id=None): - executions = qinlingclient(request).function_executions.list() - - for e in executions: - set_result(e) - - if function_id: - executions = [e for e in executions - if e.function_id == function_id] - return executions - - -@profiler.trace -def execution_get(request, execution_id): - execution = qinlingclient(request).function_executions.get(execution_id) - set_result(execution) - return execution - - -@profiler.trace -def execution_create(request, function_id, version=0, - sync=True, input=None): - execution = qinlingclient(request).function_executions.\ - create(function_id, version, sync, input) - return execution - - -@profiler.trace -def execution_delete(request, execution_id): - qinlingclient(request).function_executions.delete(execution_id) - - -@profiler.trace -def execution_log_get(request, execution_id): - try: - jr = qinlingclient(request).\ - function_executions.http_client.json_request - resp, body = jr('/v1/executions/%s/log' % execution_id, 'GET') - raw_logs = resp._content - except Exception: - raw_logs = "" - return raw_logs - - -@profiler.trace -def versions_list(request, function_id): - versions = qinlingclient(request).function_versions.list(function_id) - return versions - - -@profiler.trace -def version_get(request, function_id, version_number): - version = qinlingclient(request).function_versions.get(function_id, - version_number) - return version - - -@profiler.trace -def version_create(request, function_id, description=""): - version = qinlingclient(request).function_versions.create(function_id, - description) - return version - - -@profiler.trace -def version_delete(request, function_id, version_number): - qinlingclient(request).function_versions.delete(function_id, - version_number) diff --git a/qinling_dashboard/conf/qinling_policy.json b/qinling_dashboard/conf/qinling_policy.json deleted file mode 100644 index 93a69a8..0000000 --- a/qinling_dashboard/conf/qinling_policy.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "context_is_admin": "role:admin or is_admin:1", - "owner" : "project_id:%(project_id)s", - "admin_or_owner": "rule:context_is_admin or rule:owner", - "default": "rule:admin_or_owner", - - "runtime:create": "rule:context_is_admin", - - "function:create": "rule:admin_or_owner", - "function:update": "rule:admin_or_owner", - "function:delete": "rule:admin_or_owner", - "function:download": "rule:admin_or_owner", - - "function_execution:create": "rule:admin_or_owner", - "function_execution:delete": "rule:admin_or_owner", - "function_execution:log_show": "rule:admin_or_owner", - - "function_version:create": "rule:admin_or_owner", - "function_version:delete": "rule:admin_or_owner" -} diff --git a/qinling_dashboard/content/__init__.py b/qinling_dashboard/content/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qinling_dashboard/content/executions/__init__.py b/qinling_dashboard/content/executions/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qinling_dashboard/content/executions/forms.py b/qinling_dashboard/content/executions/forms.py deleted file mode 100644 index 71b20a2..0000000 --- a/qinling_dashboard/content/executions/forms.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2012 Nebula, 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. - -""" -Views for managing volumes. -""" - -from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ - -from horizon import exceptions -from horizon import forms -from horizon import messages - -from qinling_dashboard import api -from qinling_dashboard import utils as q_utils -from qinling_dashboard import validators - - -class CreateExecutionForm(forms.SelfHandlingForm): - - func = forms.ChoiceField( - label=_("Function"), - help_text=_("Function to execute."), - required=True) - - version = forms.IntegerField( - label=_("Version"), - required=False, - initial=0 - ) - - sync = forms.BooleanField( - label=_("Sync"), - required=False, - help_text=_("Check this item if you would like sync execution."), - initial=True - ) - - input_params = forms.CharField( - label=_('Input'), - help_text=_('Specify input parmeters like name1=value2. ' - 'One line is equivalent of one input parameter.'), - validators=[validators.validate_key_value_pairs], - widget=forms.widgets.Textarea(), - required=False) - - def __init__(self, request, *args, **kwargs): - super(CreateExecutionForm, self).__init__(request, *args, **kwargs) - self.fields['func'].choices = self.get_func_choices(request) - - try: - if 'function_id' in request.GET and 'version' in request.GET: - self.prepare_source_fields_if_function_specified(request) - except Exception: - pass - - def prepare_source_fields_if_function_specified(self, request): - try: - function_id = request.GET['function_id'] - func = api.qinling.function_get(request, function_id) - - self.fields['func'].choices = [(function_id, func.name or func.id)] - self.fields['func'].initial = function_id - - self.fields['version'].initial = request.GET['version'] - except Exception: - msg = _('Unable to load the specified function. %s') - exceptions.handle(request, msg % request.GET['function_id']) - - def clean(self): - cleaned = super(CreateExecutionForm, self).clean() - version_number = cleaned.get('version') - - # version number is not specified or specified as zero. - if not version_number: - return cleaned - - function_id = cleaned.get('func') - - versions = api.qinling.versions_list(self.request, function_id) - - # in case versions are returned as empty array. - if not versions and not version_number: - return cleaned - - available_versions = [v.version_number for v in versions] - if version_number not in available_versions: - msg = _('This function does not ' - 'have specified version number: %s') % version_number - raise forms.ValidationError(msg) - - return cleaned - - def get_func_choices(self, request): - try: - functions = api.qinling.functions_list(request) - except Exception: - functions = [] - - function_choices = [(f.id, f.name or f.id) for f in functions] - if len(function_choices) == 0: - function_choices = [('', _('No functions available.'))] - return function_choices - - def handle(self, request, data): - try: - function_id = data['func'] - version = int(data['version']) - sync = data['sync'] - inp = \ - q_utils.convert_raw_input_to_api_format(data['input_params']) - api.qinling.execution_create(request, function_id, version, - sync, inp) - message = _('Created execution of "%s"') % function_id - messages.success(request, message) - return True - except Exception: - redirect = reverse("horizon:project:executions:index") - exceptions.handle(request, - _("Unable to create execution."), - redirect=redirect) diff --git a/qinling_dashboard/content/executions/panel.py b/qinling_dashboard/content/executions/panel.py deleted file mode 100644 index 05b12e5..0000000 --- a/qinling_dashboard/content/executions/panel.py +++ /dev/null @@ -1,22 +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. - -from django.utils.translation import ugettext_lazy as _ - -import horizon - - -class Executions(horizon.Panel): - name = _("Executions") - slug = "executions" - permissions = ('openstack.services.function-engine',) diff --git a/qinling_dashboard/content/executions/tables.py b/qinling_dashboard/content/executions/tables.py deleted file mode 100644 index 8549004..0000000 --- a/qinling_dashboard/content/executions/tables.py +++ /dev/null @@ -1,172 +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. - -from django import template - -from django.urls import reverse - -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy - -from horizon import tables - -from qinling_dashboard import api -from qinling_dashboard import utils - - -class CreateExecution(tables.LinkAction): - name = "create" - verbose_name = _("Create Execution") - url = "horizon:project:executions:create" - classes = ("ajax-modal", "btn-create") - policy_rules = (("function_engine", "function_execution:create"),) - icon = "plus" - ajax = True - - -class LogLink(tables.LinkAction): - name = "console" - verbose_name = _("Show Execution Logs") - url = "horizon:project:executions:detail" - classes = ("btn-console",) - policy_rules = (("function_engine", "function_execution:log_show"),) - - def get_link_url(self, datum): - base_url = super(LogLink, self).get_link_url(datum) - return base_url + "?tab=execution_details__execution_logs" - - -class DeleteExecution(tables.DeleteAction): - policy_rules = (("function_engine", "function_execution:delete"),) - help_text = _("Deleted executions are not recoverable.") - - @staticmethod - def action_present(count): - return ungettext_lazy( - u"Delete Execution", - u"Delete Executions", - count - ) - - @staticmethod - def action_past(count): - return ungettext_lazy( - u"Delete Execution", - u"Delete Executions", - count - ) - - def delete(self, request, execution): - api.qinling.execution_delete(request, execution) - - -class ExecutionsFilterAction(tables.FilterAction): - - def filter(self, table, functions, filter_string): - """Naive case-insensitive search.""" - q = filter_string.lower() - return [function for function in functions - if q in function.name.lower()] - - -class FunctionIDColumn(tables.Column): - - def get_link_url(self, datum): - function_id = datum.function_id - result = reverse(self.link, args=(function_id,)) - result += "?tab=function_details__overview" - return result - - -def get_result(datum): - template_name = 'project/executions/_execution_result.html' - result = datum.result - - if result is None: - return result - - duration = result.get('duration', '') - output = result.get('output', '') - - if isinstance(output, dict) and 'error' in output: - output = output.get('error') - - context = { - "duration": duration, - "output": output - } - return template.loader.render_to_string(template_name, context) - - -class UpdateRow(tables.Row): - ajax = True - - def get_data(self, request, execution_id): - execution = api.qinling.execution_get(request, execution_id) - return execution - - -class ExecutionsTable(tables.DataTable): - - id = tables.Column("id", - verbose_name=_("Id"), - link="horizon:project:executions:detail") - - function_id = FunctionIDColumn("function_id", - verbose_name=_("Function ID"), - link="horizon:project:functions:detail") - - function_version = tables.Column("function_version", - verbose_name=_("Function Version")) - - description = tables.Column("description", - verbose_name=_("Description")) - - input = tables.Column("input", verbose_name=_("Input")) - - result = tables.Column(get_result, - verbose_name=_("Result")) - - sync = tables.Column("sync", verbose_name=_("Sync")) - - created_at = tables.Column("created_at", - verbose_name=_("Created At")) - - updated_at = tables.Column("updated_at", - verbose_name=_("Updated At")) - - project_id = tables.Column("project_id", - verbose_name=_("Project ID")) - - status = tables.Column( - "status", - status=True, - status_choices=utils.FUNCTION_ENGINE_STATUS_CHOICES, - display_choices=utils.FUNCTION_ENGINE_STATUS_DISPLAY_CHOICES) - - def get_object_display(self, datum): - return datum.id - - class Meta(object): - name = "executions" - verbose_name = _("Executions") - status_columns = ["status"] - multi_select = True - row_class = UpdateRow - - table_actions = ( - CreateExecution, - DeleteExecution, - ExecutionsFilterAction, - ) - row_actions = (LogLink, - DeleteExecution,) diff --git a/qinling_dashboard/content/executions/tabs.py b/qinling_dashboard/content/executions/tabs.py deleted file mode 100644 index 84f9700..0000000 --- a/qinling_dashboard/content/executions/tabs.py +++ /dev/null @@ -1,49 +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 logging - -from django.utils.translation import ugettext_lazy as _ - -from horizon import tabs - - -LOG = logging.getLogger(__name__) - - -class ExecutionOverviewTab(tabs.Tab): - name = _("Overview") - slug = "overview" - template_name = "project/executions/_detail_overview.html" - - def get_context_data(self, request): - execution = self.tab_group.kwargs["execution"] - return {"execution": execution, - "result": execution.result} - - -class ExecutionLogsTab(tabs.Tab): - name = _("Execution Logs") - slug = "execution_logs" - template_name = "project/executions/_detail_logs.html" - - def get_context_data(self, request): - execution_logs = self.tab_group.kwargs["execution_logs"] - return {"execution_logs": execution_logs} - - -class ExecutionDetailTabs(tabs.TabGroup): - slug = "execution_details" - tabs = (ExecutionOverviewTab, - ExecutionLogsTab) - sticky = True - show_single_tab = False diff --git a/qinling_dashboard/content/executions/templates/executions/_create.html b/qinling_dashboard/content/executions/templates/executions/_create.html deleted file mode 100644 index 71e5a1b..0000000 --- a/qinling_dashboard/content/executions/templates/executions/_create.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} -{% block modal-body-right %} -

{% trans "Description:" %}

-

{% trans "Create a new execution of function." %}

-{% endblock %} diff --git a/qinling_dashboard/content/executions/templates/executions/_detail_logs.html b/qinling_dashboard/content/executions/templates/executions/_detail_logs.html deleted file mode 100644 index 7c5fcaf..0000000 --- a/qinling_dashboard/content/executions/templates/executions/_detail_logs.html +++ /dev/null @@ -1,2 +0,0 @@ -{% load i18n %} -
{{ execution_logs }}
diff --git a/qinling_dashboard/content/executions/templates/executions/_detail_overview.html b/qinling_dashboard/content/executions/templates/executions/_detail_overview.html deleted file mode 100644 index 86a2d42..0000000 --- a/qinling_dashboard/content/executions/templates/executions/_detail_overview.html +++ /dev/null @@ -1,57 +0,0 @@ -{% load i18n %} - -
-
- -
{% trans "ID" %}
-
{{ execution.id }}
- -
{% trans "Function ID" %}
-
{{ execution.function_id }}
- -
{% trans "Function Version" %}
-
{{ execution.function_version }}
- -
{% trans "Description" %}
-
{{ execution.description }}
- -
{% trans "Input" %}
-
{{ execution.input }}
- -
{% trans "Result" %}
-
- - - - - - - - - - - - - -
{% trans "Duration" %}{% trans "Output" %}
{{ result.duration }}{{ result.output }}
-
- -
{% trans "Sync" %}
-
{{ execution.sync }}
- -
{% trans "Project ID" %}
-
{{ execution.project_id }}
- -
{% trans "Created At" %}
-
{{ execution.created_at|parse_isotime }}
- -
{% trans "Updated At" %}
-
{{ execution.updated_at|parse_isotime }}
- -
{% trans "Status" %}
- {% with execution.status|title as rt_status %} -
{% trans rt_status context "current status of a runtime" %}
- {% endwith %} - -
-
diff --git a/qinling_dashboard/content/executions/templates/executions/_execution_result.html b/qinling_dashboard/content/executions/templates/executions/_execution_result.html deleted file mode 100644 index dc0cf86..0000000 --- a/qinling_dashboard/content/executions/templates/executions/_execution_result.html +++ /dev/null @@ -1,3 +0,0 @@ -{% load i18n %} -{% trans 'Duration' %}: {{ duration }}
-{% trans 'Output' %}: {{ output }} diff --git a/qinling_dashboard/content/executions/templates/executions/create.html b/qinling_dashboard/content/executions/templates/executions/create.html deleted file mode 100644 index 02d01a1..0000000 --- a/qinling_dashboard/content/executions/templates/executions/create.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Create Execution" %}{% endblock %} - -{% block main %} - {% include 'project/executions/_create.html' %} -{% endblock %} diff --git a/qinling_dashboard/content/executions/templates/executions/detail.html b/qinling_dashboard/content/executions/templates/executions/detail.html deleted file mode 100644 index ab77f34..0000000 --- a/qinling_dashboard/content/executions/templates/executions/detail.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Execution Details" %}{% endblock %} - -{% block main %} -
-
- {{ tab_group.render }} -
-
-{% endblock %} diff --git a/qinling_dashboard/content/executions/urls.py b/qinling_dashboard/content/executions/urls.py deleted file mode 100644 index 011df33..0000000 --- a/qinling_dashboard/content/executions/urls.py +++ /dev/null @@ -1,25 +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. - -from django.conf.urls import url - -from qinling_dashboard.content.executions import views - - -urlpatterns = [ - url(r'^$', views.IndexView.as_view(), name='index'), - url(r'^create', views.CreateExecutionView.as_view(), name='create'), - url(r'^(?P[^/]+)/$', - views.DetailView.as_view(), name='detail'), - url(r'^(?P[^/]+)/\?tab=execution_details__execution_logs$', - views.DetailView.as_view(), name='detail_execution_logs'), -] diff --git a/qinling_dashboard/content/executions/views.py b/qinling_dashboard/content/executions/views.py deleted file mode 100644 index fdd0535..0000000 --- a/qinling_dashboard/content/executions/views.py +++ /dev/null @@ -1,107 +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. - -from django.urls import reverse -from django.urls import reverse_lazy -from django.utils.translation import ugettext_lazy as _ - -from horizon import exceptions -from horizon import forms -from horizon import tables -from horizon import tabs - -from horizon.utils import memoized - -from qinling_dashboard import api -from qinling_dashboard.content.executions import forms as project_forms -from qinling_dashboard.content.executions import tables as project_tables -from qinling_dashboard.content.executions import tabs as project_tabs - - -class CreateExecutionView(forms.ModalFormView): - - form_class = project_forms.CreateExecutionForm - modal_header = submit_label = page_title = _("Create Execution") - template_name = 'project/executions/create.html' - submit_url = reverse_lazy("horizon:project:executions:create") - success_url = reverse_lazy("horizon:project:executions:index") - - -class IndexView(tables.DataTableView): - - table_class = project_tables.ExecutionsTable - page_title = _("Executions") - - def get_data(self): - try: - executions = api.qinling.executions_list(self.request) - except Exception: - executions = [] - msg = _('Unable to retrieve executions list.') - exceptions.handle(self.request, msg) - return executions - - -class DetailView(tabs.TabbedTableView): - tab_group_class = project_tabs.ExecutionDetailTabs - template_name = 'project/executions/detail.html' - page_title = _("Execution Details: {{ resource_name }}") - failure_url = reverse_lazy('horizon:project:executions:index') - - @memoized.memoized_method - def _get_data(self): - execution_id = self.kwargs['execution_id'] - try: - execution = api.qinling.execution_get(self.request, execution_id) - except Exception: - exceptions.handle( - self.request, - _('Unable to retrieve ' - 'details for execution "%s".') % execution_id, - redirect=self.failure_url - ) - return execution - - def _get_execution_logs(self): - execution_id = self.kwargs['execution_id'] - try: - execution_logs = api.qinling.execution_log_get(self.request, - execution_id) - except Exception: - execution_logs = "" - msg = _('Unable to retrieve execution logs.') - exceptions.handle(self.request, msg) - return execution_logs - - def get_context_data(self, **kwargs): - context = super(DetailView, self).get_context_data(**kwargs) - execution = self._get_data() - table = project_tables.ExecutionsTable(self.request) - context["execution"] = execution - context["url"] = self.get_redirect_url() - context["actions"] = table.render_row_actions(execution) - context["table_id"] = "execution" - context["resource_name"] = execution.id - context["object_id"] = execution.id - return context - - def get_tabs(self, request, *args, **kwargs): - execution = self._get_data() - execution_logs = self._get_execution_logs() - return self.tab_group_class(request, - execution=execution, - execution_logs=execution_logs, - **kwargs) - - @staticmethod - def get_redirect_url(): - return reverse('horizon:project:executions:index') diff --git a/qinling_dashboard/content/functions/__init__.py b/qinling_dashboard/content/functions/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qinling_dashboard/content/functions/forms.py b/qinling_dashboard/content/functions/forms.py deleted file mode 100644 index 90e8575..0000000 --- a/qinling_dashboard/content/functions/forms.py +++ /dev/null @@ -1,455 +0,0 @@ -# Copyright 2012 Nebula, 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. - -from django.urls import reverse - -from django.utils.translation import ugettext_lazy as _ - -from horizon import exceptions -from horizon import forms -from horizon import messages - -from qinling_dashboard import api - -from qinling_dashboard.utils import calculate_md5 - -from qinling_dashboard import validators - - -CPU_MIN_VALUE = 100 -CPU_MAX_VALUE = 300 -MEMORY_MIN_VALUE = 33554432 -MEMORY_MAX_VALUE = 134217728 - - -CPU_HELP_TEXT = _("Limit of cpu resource(unit: millicpu). Range: {0} ~ {1}").\ - format(CPU_MIN_VALUE, CPU_MAX_VALUE) - -MEMORY_HELP_TEXT = _("Limit of memory resource(unit: bytes). " - "Range: {0} ~ {1} (bytes).").format(MEMORY_MIN_VALUE, - MEMORY_MAX_VALUE) - -UPLOAD_PACKAGE_LABEL = _('Package') -UPLOAD_SWIFT_CONTAINER_LABEL = _('Swift Container') -UPLOAD_SWIFT_OBJECT_LABEL = _('Swift Object') -UPLOAD_IMAGE_LABEL = _('Image') - -CODE_TYPE_CHOICES = [('package', UPLOAD_PACKAGE_LABEL), - ('swift', UPLOAD_SWIFT_OBJECT_LABEL), - ('image', UPLOAD_IMAGE_LABEL)] - - -class CreateFunctionForm(forms.SelfHandlingForm): - - name = forms.CharField(max_length=255, - label=_("Name"), - validators=[validators.validate_one_line_string], - required=False) - - description = forms.CharField( - max_length=255, - widget=forms.Textarea( - attrs={'class': 'modal-body-fixed-width', - 'rows': 3}), - label=_("Description"), - required=False) - - cpu = forms.IntegerField(label=_("CPU"), - help_text=CPU_HELP_TEXT, - min_value=CPU_MIN_VALUE, - max_value=CPU_MAX_VALUE, - required=False) - - memory_size = forms.IntegerField(label=_("Memory Size"), - help_text=MEMORY_HELP_TEXT, - min_value=MEMORY_MIN_VALUE, - max_value=MEMORY_MAX_VALUE, - required=False) - - code_type = forms.ThemableChoiceField( - label=_("Code Type"), - help_text=_("Select Your Code Type."), - widget=forms.ThemableSelectWidget( - attrs={'class': 'switchable', - 'data-slug': 'code_type'} - ), - choices=CODE_TYPE_CHOICES, - required=True) - - package_file = forms.FileField( - label=UPLOAD_PACKAGE_LABEL, - help_text=_('Code package zip file path.'), - widget=forms.FileInput( - attrs={ - 'class': 'switched', - 'data-switch-on': 'code_type', - 'data-code_type-package': UPLOAD_PACKAGE_LABEL, - }, - ), - required=False) - - entry = forms.CharField( - label=_("Entry"), - help_text=_('Function entry in the format of ' - '.'), - validators=[validators.validate_one_line_string], - widget=forms.TextInput(attrs={ - 'class': 'switched', - 'data-switch-on': 'code_type', - 'data-code_type-package': _("Entry") - }), - required=False) - - runtime = forms.ThemableChoiceField( - label=_("Runtime"), - widget=forms.SelectWidget(attrs={ - 'class': 'switched', - 'data-switch-on': 'code_type', - 'data-code_type-package': _("Runtime") - }), - required=False) - - swift_container = forms.CharField( - label=UPLOAD_SWIFT_CONTAINER_LABEL, - help_text=_('Container name in Swift.'), - validators=[validators.validate_one_line_string], - widget=forms.TextInput(attrs={ - 'class': 'switched', - 'data-switch-on': 'code_type', - 'data-code_type-swift': UPLOAD_SWIFT_CONTAINER_LABEL - }), - required=False) - - swift_object = forms.CharField( - label=UPLOAD_SWIFT_OBJECT_LABEL, - help_text=_('Object name in Swift.'), - validators=[validators.validate_one_line_string], - widget=forms.TextInput(attrs={ - 'class': 'switched', - 'data-switch-on': 'code_type', - 'data-code_type-swift': UPLOAD_SWIFT_OBJECT_LABEL - }), - required=False) - - entry_swift = forms.CharField( - label=_("Entry"), - help_text=_('Function entry in the format of ' - '.'), - validators=[validators.validate_one_line_string], - widget=forms.TextInput(attrs={ - 'class': 'switched', - 'data-switch-on': 'code_type', - 'data-code_type-swift': _("Entry") - }), - required=False) - - runtime_swift = forms.ThemableChoiceField( - label=_("Runtime"), - widget=forms.SelectWidget(attrs={ - 'class': 'switched', - 'data-switch-on': 'code_type', - 'data-code_type-swift': _("Runtime") - }), - required=False) - - image = forms.CharField( - label=UPLOAD_IMAGE_LABEL, - help_text=_('Image name in Docker hub.'), - validators=[validators.validate_one_line_string], - widget=forms.TextInput(attrs={ - 'class': 'switched', - 'data-switch-on': 'code_type', - 'data-code_type-image': UPLOAD_IMAGE_LABEL - }), - required=False) - - def get_runtime_choices(self, request): - try: - runtimes = api.qinling.runtimes_list(request) - except Exception: - runtimes = [] - exceptions.handle(request, _('Unable to retrieve runtimes.')) - - runtime_list = [(runtime.id, runtime.name) for runtime in runtimes - if runtime.status == 'available'] - - runtime_list.sort() - - if not runtime_list: - runtime_list.insert(0, ("", _("No runtimes found"))) - return runtime_list - - def __init__(self, request, *args, **kwargs): - super(CreateFunctionForm, self).__init__(request, *args, **kwargs) - runtime_choices = self.get_runtime_choices(request) - self.fields['runtime'].choices = runtime_choices - self.fields['runtime_swift'].choices = runtime_choices - - def _validation_for_swift_case(self, cleaned): - swift_container = cleaned.get('swift_container', None) - swift_object = cleaned.get('swift_object', None) - if not all([swift_container, swift_object]): - msg = _('You must specify container and object ' - 'both in case code type is Swift.') - raise forms.ValidationError(msg) - - runtime = cleaned.get('runtime_swift', None) - if not runtime: - msg = _('You must specify runtime.') - raise forms.ValidationError(msg) - - def _validation_for_image_case(self, cleaned): - image = cleaned.get('image', None) - if not image: - msg = _('You must specify Docker image.') - raise forms.ValidationError(msg) - - def _get_package_file(self, cleaned): - package_file = cleaned.get('package_file', None) - return package_file - - def _validation_for_package_case(self, cleaned): - package_file = self._get_package_file(cleaned) - - if not package_file: - msg = _('You must specify package file.') - raise forms.ValidationError(msg) - - runtime = cleaned.get('runtime', None) - if not runtime: - msg = _('You must specify runtime.') - raise forms.ValidationError(msg) - - def clean(self): - cleaned = super(CreateFunctionForm, self).clean() - - code_type = cleaned['code_type'] - - if code_type == 'package': - self._validation_for_package_case(cleaned) - - if code_type == 'swift': - self._validation_for_swift_case(cleaned) - - if code_type == 'image': - self._validation_for_image_case(cleaned) - - return cleaned - - def handle_package_case(self, params, context, update=False): - upload_files = self.request.FILES - - package = upload_files.get('package_file') - md5sum = calculate_md5(package) - code = {'source': 'package', 'md5sum': md5sum} - - # case1: creation case. - # Package upload is required in creation case. - # case2: update case. - # In case update, package/code are only added - # when user specify them. - if not update or (update and package): - package = [ck for ck in package.chunks()][0] - params.update({ - 'package': package, - 'code': code, - }) - - if not update and context.get('runtime'): - params.update({'runtime': context.get('runtime')}) - - self._handle_entry_for_package(params, context, update) - - def _handle_entry_for_package(self, params, context, update=False): - if update: - params.update({'entry': context.get('entry')}) - else: - if context.get('entry'): - params.update({'entry': context.get('entry')}) - - def handle_swift_case(self, params, context, update=False): - swift_container = context.get('swift_container') - swift_object = context.get('swift_object') - - if not update or all([not update, swift_container, swift_object]): - code = { - 'source': 'swift', - 'swift': { - 'container': swift_container, - 'object': swift_object - } - } - params.update({'code': code}) - - if not update and context.get('runtime_swift'): - params.update({'runtime': context.get('runtime_swift')}) - - if not update and context.get('entry_swift'): - params.update({'entry': context.get('entry_swift')}) - - def handle_image_case(self, params, context, update=False): - if not update or all([not update, context.get('image')]): - code = { - 'source': 'image', - 'image': context.get('image') - } - params.update({'code': code}) - - def handle(self, request, context): - params = {} - - # basic parameters - if context.get('name'): - params.update({'name': context.get('name')}) - - if context.get('description'): - params.update({'description': context.get('description')}) - - if context.get('cpu'): - params.update({'cpu': int(context.get('cpu'))}) - - if context.get('memory_size'): - params.update({'memory_size': int(context.get('memory_size'))}) - - code_type = context.get('code_type') - - if code_type == 'package': - self.handle_package_case(params, context) - - elif code_type == 'swift': - self.handle_swift_case(params, context) - - elif code_type == 'image': - self.handle_image_case(params, context) - - try: - api.qinling.function_create(request, **params) - message = _('Created function "%s"') % params.get('name', - 'unknown name') - messages.success(request, message) - return True - except Exception: - redirect = reverse("horizon:project:functions:index") - exceptions.handle(request, - _("Unable to create function."), - redirect=redirect) - - -class UpdateFunctionForm(CreateFunctionForm): - - function_id = forms.CharField(widget=forms.HiddenInput(), - required=False) - - code_type = forms.ThemableChoiceField( - label=_("Code Type"), - help_text=_("Code Type can not be changed when you update function."), - widget=forms.TextInput( - attrs={'readonly': 'readonly'} - ), - choices=CODE_TYPE_CHOICES, - required=True) - - # override this to skip - def clean(self): - cleaned = super(forms.SelfHandlingForm, self).clean() - return cleaned - - def __init__(self, request, *args, **kwargs): - super(UpdateFunctionForm, self).__init__(request, *args, **kwargs) - - code_type = self.initial.get('code_type') - - # written field names here will be regarded as updatable - common_fields = ['name', 'description', - 'code_type', 'function_id'] - available_fields = { - 'package': ['package_file', 'entry', 'cpu', 'memory_size'], - 'swift': [], - 'image': [], - } - available_fields = available_fields[code_type] + common_fields - field_names = [fn for fn in self.fields.keys()] - for field_name in field_names: - if field_name not in available_fields: - del self.fields[field_name] - - def handle(self, request, context): - # basic parameters - params = { - 'name': context.get('name', ''), - 'description': context.get('description', '') - } - - if context.get('cpu'): - params.update({'cpu': int(context.get('cpu'))}) - - if context.get('memory_size'): - params.update({'memory_size': int(context.get('memory_size'))}) - - code_type = context.get('code_type') - - if code_type == 'package': - self.handle_package_case(params, context, update=True) - - elif code_type == 'swift': - self.handle_swift_case(params, context, update=True) - - elif code_type == 'image': - self.handle_image_case(params, context, update=True) - - function_id = context['function_id'] - try: - api.qinling.function_update(request, function_id, **params) - message = _('Updated function "%s"') % params.get('name', - 'unknown name') - messages.success(request, message) - return True - except Exception: - redirect = reverse("horizon:project:functions:index") - exceptions.handle(request, - _("Unable to update function %s") % function_id, - redirect=redirect) - - -class CreateFunctionVersionForm(forms.SelfHandlingForm): - - function_id = forms.CharField( - label=_("Function ID"), - help_text=_("Function which new version will be created."), - widget=forms.TextInput( - attrs={'readonly': 'readonly'} - ), - required=False) - - description = forms.CharField( - max_length=255, - widget=forms.Textarea( - attrs={'class': 'modal-body-fixed-width', - 'rows': 3}), - label=_("Description"), - required=False) - - def handle(self, request, data): - try: - function_id = data['function_id'] - description = data['description'] - api.qinling.version_create(request, function_id, description) - message = _('Created new version of "%s"') % function_id - messages.success(request, message) - return True - except Exception: - redirect = reverse("horizon:project:functions:index") - msg = _("Unable to create execution.") - exceptions.handle(request, msg, redirect=redirect) diff --git a/qinling_dashboard/content/functions/panel.py b/qinling_dashboard/content/functions/panel.py deleted file mode 100644 index 84b6a34..0000000 --- a/qinling_dashboard/content/functions/panel.py +++ /dev/null @@ -1,22 +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. - -from django.utils.translation import ugettext_lazy as _ - -import horizon - - -class Functions(horizon.Panel): - name = _("Functions") - slug = "functions" - permissions = ('openstack.services.function-engine',) diff --git a/qinling_dashboard/content/functions/tables.py b/qinling_dashboard/content/functions/tables.py deleted file mode 100644 index acee789..0000000 --- a/qinling_dashboard/content/functions/tables.py +++ /dev/null @@ -1,291 +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. - -from django.urls import reverse - -from django.utils.http import urlencode - -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy - -from horizon import tables - -from qinling_dashboard import api - -from qinling_dashboard.content.executions import tables as e_tables - - -class CreateFunction(tables.LinkAction): - name = "create" - verbose_name = _("Create Function") - url = "horizon:project:functions:create" - classes = ("ajax-modal", "btn-create") - policy_rules = (("function_engine", "function:create"),) - icon = "plus" - ajax = True - - -class CreateFunctionVersion(tables.LinkAction): - name = "create_version" - verbose_name = _("Create Version") - url = "horizon:project:functions:create_version" - classes = ("ajax-modal",) - icon = "plus" - policy_rules = (("function_engine", "function:version_create"),) - - def allowed(self, request, datum): - """Function versioning is only allowed for package type function.""" - code = datum.code - if code['source'] == 'package': - return True - return False - - -class UpdateFunction(tables.LinkAction): - name = "update" - verbose_name = _("Update Function") - url = "horizon:project:functions:update" - classes = ("ajax-modal",) - policy_rules = (("function_engine", "function:update"),) - icon = "edit" - ajax = True - - -class DownloadFunction(tables.LinkAction): - name = "download" - verbose_name = _("Download Function") - url = "horizon:project:functions:download" - icon = "download" - policy_rules = (("function_engine", "function:download"),) - - def allowed(self, request, datum): - """Function downloading is only allowed for package type function.""" - code = datum.code - if code['source'] == 'package': - return True - return False - - -class DeleteFunction(tables.DeleteAction): - policy_rules = (("function_engine", "function:delete"),) - help_text = _("Deleted functions are not recoverable.") - - @staticmethod - def action_present(count): - return ungettext_lazy( - u"Delete Function", - u"Delete Functions", - count - ) - - @staticmethod - def action_past(count): - return ungettext_lazy( - u"Delete Function", - u"Delete Functions", - count - ) - - def delete(self, request, func): - api.qinling.function_delete(request, func) - - -class FunctionsFilterAction(tables.FilterAction): - - def filter(self, table, functions, filter_string): - """Naive case-insensitive search.""" - q = filter_string.lower() - return [function for function in functions - if q in function.name.lower()] - - -class RuntimeIDColumn(tables.Column): - - def get_link_url(self, datum): - if not hasattr(datum, 'id'): - return None - runtime_id = datum.runtime_id - result = reverse(self.link, args=(runtime_id,)) - return result - - -def get_memory_size(function): - return "{:,}".format(function.memory_size) - - -class FunctionsTable(tables.DataTable): - - id = tables.Column("id", - verbose_name=_("Id"), - link="horizon:project:functions:detail") - - name = tables.Column("name", - verbose_name=_("Name")) - - description = tables.Column("description", - verbose_name=_("Description")) - - runtime_id = RuntimeIDColumn("runtime_id", - verbose_name=_("Runtime ID"), - link="horizon:project:runtimes:detail") - - entry = tables.Column("entry", - verbose_name=_("Entry")) - - created_at = tables.Column("created_at", - verbose_name=_("Created At")) - - updated_at = tables.Column("updated_at", - verbose_name=_("Updated At")) - - cpu = tables.Column("cpu", verbose_name=_("CPU (Milli CPU)")) - memory_size = tables.Column(get_memory_size, - verbose_name=_("Memory Size (Bytes)")) - - def get_object_display(self, datum): - return datum.id - - class Meta(object): - name = "functions" - verbose_name = _("Functions") - multi_select = True - - table_actions = ( - CreateFunction, - DeleteFunction, - FunctionsFilterAction - ) - row_actions = ( - UpdateFunction, - DownloadFunction, - CreateFunctionVersion, - DeleteFunction - ) - - -class DeleteFunctionVersion(tables.DeleteAction): - policy_rules = (("function_engine", "function_version:delete"),) - help_text = _("Deleted function versions are not recoverable.") - - @staticmethod - def action_present(count): - return ungettext_lazy( - u"Delete Function Version", - u"Delete Function Versions", - count - ) - - @staticmethod - def action_past(count): - return ungettext_lazy( - u"Delete Function Version", - u"Delete Function Versions", - count - ) - - def delete(self, request, version_id): - functions = api.qinling.functions_list(request, with_version=True) - - for f in functions: - for v in f.versions: - if v.id == version_id: - version_number = v.version_number - function_id = v.function_id - api.qinling.version_delete(request, - function_id, version_number) - - -class CreateFunctionExecution(tables.LinkAction): - name = "create_execution_from_function" - verbose_name = _("Create Execution") - url = "horizon:project:functions:create_execution" - classes = ("ajax-modal",) - policy_rules = (("function_engine", "function_execution:create"),) - icon = "plus" - - def get_link_url(self, datum): - function_id = datum.function_id - version_number = datum.version_number - - base_url = reverse(self.url, args=(function_id,)) - - params = urlencode({"function_id": function_id, - "version": version_number}) - return "?".join([base_url, params]) - - -class FunctionVersionColumn(tables.Column): - - def get_link_url(self, datum): - version_number = datum.version_number - function_id = self.table.kwargs['function_id'] - result = reverse(self.link, args=(function_id, - version_number)) - return result - - -class FunctionColumn(tables.Column): - - def get_link_url(self, datum): - function_id = datum.function_id - result = reverse(self.link, args=(function_id,)) - result += "?tab=function_details__overview" - return result - - -class FunctionVersionsTable(tables.DataTable): - - id = FunctionVersionColumn("id", - verbose_name=_("Id"), - link="horizon:project:functions:version_detail") - - description = tables.Column("description", - verbose_name=_("Description")) - - function_id = FunctionColumn("function_id", - verbose_name=_("Function ID"), - link="horizon:project:functions:detail") - - version_number = tables.Column("version_number", - verbose_name=_("Version Number")) - - count = tables.Column("count", verbose_name=_("Count")) - - created_at = tables.Column("created_at", - verbose_name=_("Created At")) - - updated_at = tables.Column("updated_at", - verbose_name=_("Updated At")) - - def get_object_display(self, datum): - return datum.id - - class Meta(object): - name = "function_versions" - verbose_name = _("Versions") - multi_select = True - - table_actions = (DeleteFunctionVersion,) - row_actions = (CreateFunctionExecution, - DeleteFunctionVersion,) - - -class FunctionExecutionsTable(e_tables.ExecutionsTable): - - class Meta(object): - name = "function_executions" - verbose_name = _("Executions") - multi_select = True - - table_actions = (e_tables.DeleteExecution,) - row_actions = (e_tables.LogLink, - e_tables.DeleteExecution,) diff --git a/qinling_dashboard/content/functions/tabs.py b/qinling_dashboard/content/functions/tabs.py deleted file mode 100644 index 5ea229b..0000000 --- a/qinling_dashboard/content/functions/tabs.py +++ /dev/null @@ -1,83 +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 logging - -from django.utils.translation import ugettext_lazy as _ - -from horizon import tabs - -from qinling_dashboard.content.functions import tables as project_tables - - -LOG = logging.getLogger(__name__) - - -class FunctionOverviewTab(tabs.Tab): - name = _("Overview") - slug = "overview" - template_name = "project/functions/_detail_overview.html" - failure_url = 'horizon:project:functions:index' - - def get_context_data(self, request): - func = self.tab_group.kwargs['function'] - func.memory_size = "{:,}".format(func.memory_size) - return {"function": func, - "code": func.code} - - -class FunctionExecutionsTab(tabs.TableTab): - table_classes = (project_tables.FunctionExecutionsTable,) - name = _("Executions of this function") - slug = "executions_of_this_function" - template_name = "project/functions/_detail_executions.html" - # preload = False - - def get_function_executions_data(self): - return self.tab_group.kwargs['executions'] - - -class FunctionVersionsTab(tabs.TableTab): - table_classes = (project_tables.FunctionVersionsTable,) - name = _("Versions of this function") - slug = "versions_of_this_function" - template_name = "project/functions/_detail_versions.html" - - def get_function_versions_data(self): - return self.tab_group.kwargs['versions'] - - -class FunctionDetailTabs(tabs.TabGroup): - slug = "function_details" - tabs = (FunctionOverviewTab, - FunctionExecutionsTab, - FunctionVersionsTab) - sticky = True - show_single_tab = False - - -class FunctionVersionOerviewTab(tabs.Tab): - name = _("Version detail") - slug = "versions_detail_overview" - template_name = "project/functions/_detail_version_overview.html" - preload = False - - def get_context_data(self, request): - version = self.tab_group.kwargs['version'] - return {"version": version} - - -class FunctionVersionDetailTabs(tabs.TabGroup): - slug = "function_version_details" - tabs = (FunctionVersionOerviewTab,) - sticky = True - show_single_tab = False diff --git a/qinling_dashboard/content/functions/templates/functions/_create_function.html b/qinling_dashboard/content/functions/templates/functions/_create_function.html deleted file mode 100644 index 395b546..0000000 --- a/qinling_dashboard/content/functions/templates/functions/_create_function.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} -{% block form_attrs %}enctype="multipart/form-data"{% endblock %} -{% block modal-body-right %} -

{% trans "Description:" %}

-

{% trans "Create a new function." %}

-{% endblock %} diff --git a/qinling_dashboard/content/functions/templates/functions/_create_version.html b/qinling_dashboard/content/functions/templates/functions/_create_version.html deleted file mode 100644 index 177e485..0000000 --- a/qinling_dashboard/content/functions/templates/functions/_create_version.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} -{% block modal-body-right %} -

{% trans "Description:" %}

-

{% trans "Create a new version of function." %}

-{% endblock %} diff --git a/qinling_dashboard/content/functions/templates/functions/_detail_executions.html b/qinling_dashboard/content/functions/templates/functions/_detail_executions.html deleted file mode 100644 index 9976f88..0000000 --- a/qinling_dashboard/content/functions/templates/functions/_detail_executions.html +++ /dev/null @@ -1,3 +0,0 @@ -{% load i18n %} - -{{ table.render }} diff --git a/qinling_dashboard/content/functions/templates/functions/_detail_overview.html b/qinling_dashboard/content/functions/templates/functions/_detail_overview.html deleted file mode 100644 index 1eca5c6..0000000 --- a/qinling_dashboard/content/functions/templates/functions/_detail_overview.html +++ /dev/null @@ -1,58 +0,0 @@ -{% load i18n %} - -
-
- -
{% trans "ID" %}
-
{{ function.id }}
- -
{% trans "Name" %}
-
{{ function.name }}
- -
{% trans "Description" %}
-
{{ function.description }}
- -
{% trans "Count" %}
-
{{ function.count }}
- -
{% trans "Code" %}
-
- - - - - - - - - - - - - -
{% trans "Source" %}{% trans "Md5sum" %}
{{ code.source }}{{ code.md5sum }}
-
- -
{% trans "Runtime ID" %}
-
{{ function.runtime_id }}
- -
{% trans "Entry" %}
-
{{ function.entry }}
- -
{% trans "Project ID" %}
-
{{ function.project_id }}
- -
{% trans "Created At" %}
-
{{ function.created_at|parse_isotime }}
- -
{% trans "Updated At" %}
-
{{ function.updated_at|parse_isotime }}
- -
{% trans "CPU (Milli CPU)" %}
-
{{ function.cpu }}
- -
{% trans "Memory Size (Bytes)" %}
-
{{ function.memory_size }}
- -
-
diff --git a/qinling_dashboard/content/functions/templates/functions/_detail_version_overview.html b/qinling_dashboard/content/functions/templates/functions/_detail_version_overview.html deleted file mode 100644 index 8031771..0000000 --- a/qinling_dashboard/content/functions/templates/functions/_detail_version_overview.html +++ /dev/null @@ -1,31 +0,0 @@ -{% load i18n %} - -
-
- -
{% trans "ID" %}
-
{{ version.id }}
- -
{% trans "Function ID" %}
-
{{ version.function_id }}
- -
{% trans "Description" %}
-
{{ version.description }}
- -
{% trans "Version Number" %}
-
{{ version.version_number }}
- -
{% trans "Count" %}
-
{{ version.count }}
- -
{% trans "Project ID" %}
-
{{ version.project_id }}
- -
{% trans "Created At" %}
-
{{ version.created_at|parse_isotime }}
- -
{% trans "Updated At" %}
-
{{ version.updated_at|parse_isotime }}
- -
-
diff --git a/qinling_dashboard/content/functions/templates/functions/_detail_versions.html b/qinling_dashboard/content/functions/templates/functions/_detail_versions.html deleted file mode 100644 index 9976f88..0000000 --- a/qinling_dashboard/content/functions/templates/functions/_detail_versions.html +++ /dev/null @@ -1,3 +0,0 @@ -{% load i18n %} - -{{ table.render }} diff --git a/qinling_dashboard/content/functions/templates/functions/_update_function.html b/qinling_dashboard/content/functions/templates/functions/_update_function.html deleted file mode 100644 index 7c0c387..0000000 --- a/qinling_dashboard/content/functions/templates/functions/_update_function.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} -{% block form_attrs %}enctype="multipart/form-data"{% endblock %} -{% block modal-body-right %} -

{% trans "Description:" %}

-

{% trans "Update function." %}

-{% endblock %} diff --git a/qinling_dashboard/content/functions/templates/functions/create_function.html b/qinling_dashboard/content/functions/templates/functions/create_function.html deleted file mode 100644 index 56d0e53..0000000 --- a/qinling_dashboard/content/functions/templates/functions/create_function.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Create Function" %}{% endblock %} - -{% block main %} - {% include 'project/functions/_create_function.html' %} -{% endblock %} diff --git a/qinling_dashboard/content/functions/templates/functions/create_version.html b/qinling_dashboard/content/functions/templates/functions/create_version.html deleted file mode 100644 index 7308a45..0000000 --- a/qinling_dashboard/content/functions/templates/functions/create_version.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Create Function Version" %}{% endblock %} - -{% block main %} - {% include 'project/executions/_create_version.html' %} -{% endblock %} diff --git a/qinling_dashboard/content/functions/templates/functions/detail.html b/qinling_dashboard/content/functions/templates/functions/detail.html deleted file mode 100644 index 61d97dd..0000000 --- a/qinling_dashboard/content/functions/templates/functions/detail.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Function Details" %}{% endblock %} - -{% block main %} -
-
- {{ tab_group.render }} -
-
-{% endblock %} diff --git a/qinling_dashboard/content/functions/templates/functions/detail_version.html b/qinling_dashboard/content/functions/templates/functions/detail_version.html deleted file mode 100644 index 8e41598..0000000 --- a/qinling_dashboard/content/functions/templates/functions/detail_version.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Function Version Details" %}{% endblock %} - -{% block main %} -
-
- {{ tab_group.render }} -
-
-{% endblock %} diff --git a/qinling_dashboard/content/functions/templates/functions/update_function.html b/qinling_dashboard/content/functions/templates/functions/update_function.html deleted file mode 100644 index 89e8530..0000000 --- a/qinling_dashboard/content/functions/templates/functions/update_function.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Update Function" %}{% endblock %} - -{% block main %} - {% include 'project/executions/_update_function.html' %} -{% endblock %} diff --git a/qinling_dashboard/content/functions/urls.py b/qinling_dashboard/content/functions/urls.py deleted file mode 100644 index 6de296c..0000000 --- a/qinling_dashboard/content/functions/urls.py +++ /dev/null @@ -1,42 +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. - -from django.conf.urls import url - -from qinling_dashboard.content.functions import views - - -urlpatterns = [ - url(r'^$', views.IndexView.as_view(), name='index'), - url(r'^create', views.CreateFunctionView.as_view(), name='create'), - url(r'^(?P[^/]+)/update', - views.UpdateFunctionView.as_view(), name='update'), - url(r'^(?P[^/]+)/download/$', - views.download_function, name='download'), - url(r'^(?P[^/]+)/versions/create', - views.CreateFunctionVersionView.as_view(), name='create_version'), - url(r'^(?P[^/]+)/versions/(?P[^/]+)/$', - views.VersionDetailView.as_view(), name='version_detail'), - url(r'^(?P[^/]+)/functions/create_execution', - views.CreateFunctionExecutionView.as_view(), name='create_execution'), - # detail - url(r'^(?P[^/]+)/$', - views.DetailView.as_view(), name='detail'), - # detail(tab=executions) - url(r'^(?P[^/]+)/' - r'\?tab=function_details_executions_of_this_function$', - views.DetailView.as_view(), name='detail_executions'), - # detail(tab=versions) - url(r'^(?P[^/]+)/' - r'\?tab=function_details_versions_of_this_function$', - views.DetailView.as_view(), name='detail_versions'), -] diff --git a/qinling_dashboard/content/functions/views.py b/qinling_dashboard/content/functions/views.py deleted file mode 100644 index b11fb4b..0000000 --- a/qinling_dashboard/content/functions/views.py +++ /dev/null @@ -1,309 +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 io - -from django import shortcuts - -from django.http import HttpResponse -from django.urls import reverse -from django.urls import reverse_lazy -from django.utils.translation import ugettext_lazy as _ - -from horizon import exceptions -from horizon import forms -from horizon import messages -from horizon import tables -from horizon import tabs - -from horizon.utils import memoized - -from qinling_dashboard import api - -from qinling_dashboard import exceptions as q_exc - -from qinling_dashboard.content.executions import views as ex_views - -from qinling_dashboard.content.functions import forms as project_forms -from qinling_dashboard.content.functions import tables as project_tables -from qinling_dashboard.content.functions import tabs as project_tabs - - -class CreateFunctionExecutionView(ex_views.CreateExecutionView): - - modal_header = submit_label = page_title = _("Create Execution") - submit_url = "horizon:project:functions:create_execution" - success_url = "horizon:project:functions:detail" - - def get_context_data(self, **kwargs): - context = super(CreateFunctionExecutionView, self).\ - get_context_data(**kwargs) - submit_url = reverse(self.submit_url, - args=(self.kwargs['function_id'],)) - context['submit_url'] = submit_url - return context - - def get_success_url(self): - function_id = self.kwargs['function_id'] - result = reverse(self.success_url, args=(function_id,)) - result += "?tab=function_details__executions_of_this_function" - return result - - -class CreateFunctionView(forms.ModalFormView): - - form_class = project_forms.CreateFunctionForm - modal_header = submit_label = page_title = _("Create Function") - template_name = "project/functions/create_function.html" - submit_url = reverse_lazy("horizon:project:functions:create") - success_url = reverse_lazy("horizon:project:functions:index") - - -class UpdateFunctionView(forms.ModalFormView): - - form_class = project_forms.UpdateFunctionForm - modal_header = submit_label = page_title = _("Update Function") - template_name = "project/functions/update_function.html" - submit_url = "horizon:project:functions:update" - success_url = reverse_lazy("horizon:project:functions:index") - - @memoized.memoized_method - def get_object(self, *args, **kwargs): - function_id = self.kwargs['function_id'] - try: - return api.qinling.function_get(self.request, function_id) - except Exception: - redirect = reverse("horizon:project:functions:index") - msg = _('Unable to retrieve function details.') - exceptions.handle(self.request, msg, redirect=redirect) - - def get_context_data(self, **kwargs): - context = super(UpdateFunctionView, self).\ - get_context_data(**kwargs) - function_id = self.kwargs['function_id'] - context['function_id'] = function_id - context['submit_url'] = reverse(self.submit_url, args=(function_id,)) - return context - - def get_initial(self): - initial = super(UpdateFunctionView, self).get_initial() - func = self.get_object() - code = getattr(func, 'code', {}) - code_swift = code.get('swift', {}) - source = code.get('source', '') - - initial.update({ - 'function_id': func.id, - 'name': getattr(func, 'name', ''), - 'description': getattr(func, 'description', ''), - 'cpu': getattr(func, 'cpu', ''), - 'memory_size': getattr(func, 'memory_size', ''), - 'runtime_id': getattr(func, 'runtime_id', ''), - 'entry': getattr(func, 'entry', ''), - 'code_type': code.get('source', ''), - 'swift_container': code_swift.get('container', ''), - 'swift_object': code_swift.get('object', ''), - 'image': code.get('image', ''), - 'source': source, - }) - return initial - - -class CreateFunctionVersionView(forms.ModalFormView): - - form_class = project_forms.CreateFunctionVersionForm - modal_header = submit_label = page_title = _("Create Version") - template_name = "project/functions/create_version.html" - submit_url = "horizon:project:functions:create_version" - success_url = "horizon:project:functions:detail" - - def get_success_url(self): - function_id = self.kwargs['function_id'] - result = reverse(self.success_url, args=(function_id,)) - result += "?tab=function_details__versions_of_this_function" - return result - - def get_context_data(self, **kwargs): - context = super(CreateFunctionVersionView, self).\ - get_context_data(**kwargs) - function_id = self.kwargs['function_id'] - context['function_id'] = function_id - context['submit_url'] = reverse(self.submit_url, args=(function_id,)) - return context - - def get_initial(self): - initial = super(CreateFunctionVersionView, self).get_initial() - initial.update({ - 'function_id': self.kwargs["function_id"], - }) - return initial - - -class IndexView(tables.DataTableView): - - table_class = project_tables.FunctionsTable - page_title = _("Functions") - - def get_data(self): - try: - functions = api.qinling.functions_list(self.request) - except Exception: - functions = [] - msg = _('Unable to retrieve functions list.') - exceptions.handle(self.request, msg) - return functions - - -class DetailView(tabs.TabbedTableView): - tab_group_class = project_tabs.FunctionDetailTabs - template_name = 'project/functions/detail.html' - page_title = _("Function Details: {{ resource_name }}") - failure_url = reverse_lazy('horizon:project:functions:index') - - @memoized.memoized_method - def _get_data(self): - function_id = self.kwargs['function_id'] - try: - function = api.qinling.function_get(self.request, function_id) - except Exception: - exceptions.handle( - self.request, - _('Unable to retrieve ' - 'details for Function "%s".') % function_id, - redirect=self.failure_url - ) - return function - - def get_context_data(self, **kwargs): - context = super(DetailView, self).get_context_data(**kwargs) - func = self._get_data() - table = project_tables.FunctionsTable(self.request) - resource_name = func.name if func.name else func.id - context["function"] = func - context["url"] = self.get_redirect_url() - context["actions"] = table.render_row_actions(func) - context["table_id"] = "runtime" - context["resource_name"] = resource_name - context["object_id"] = func.id - return context - - def _get_executions(self): - function_id = self.kwargs['function_id'] - try: - executions = api.qinling.executions_list(self.request, function_id) - except Exception: - executions = [] - messages.error(self.request, _( - 'Unable to get executions of ' - 'this function "%s".') % function_id) - return executions - - def _get_versions(self): - function_id = self.kwargs['function_id'] - try: - versions = api.qinling.versions_list(self.request, function_id) - except Exception: - versions = [] - messages.error(self.request, _( - 'Unable to get versions of this function "%s".') % function_id) - return versions - - def get_tabs(self, request, *args, **kwargs): - func = self._get_data() - executions = self._get_executions() - versions = self._get_versions() - return self.tab_group_class(request, - function=func, - executions=executions, - versions=versions, - **kwargs) - - @staticmethod - def get_redirect_url(): - return reverse('horizon:project:functions:index') - - -class VersionDetailView(tabs.TabView): - tab_group_class = project_tabs.FunctionVersionDetailTabs - template_name = 'project/functions/detail_version.html' - page_title = _("Function Version Details: " - "{{ version.function_id }} " - "(Version Number={{ version_number }})") - failure_url = reverse_lazy('horizon:project:functions:index') - - def get_redirect_url(self, version_number=None): - function_id = self.kwargs['function_id'] - - if not version_number: - return reverse('horizon:project:functions:detail', - args=(function_id,)) - - return reverse('horizon:project:functions:version_detail', - args=(function_id, version_number)) - - @memoized.memoized_method - def get_data(self): - function_id = self.kwargs['function_id'] - version_number = int(self.kwargs['version_number']) - try: - version = api.qinling.version_get(self.request, - function_id, - version_number) - except Exception: - exceptions.handle( - self.request, - _('Unable to retrieve details for ' - 'function version "%s".') % (function_id, version_number), - redirect=self.failure_url - ) - return version - - def get_context_data(self, **kwargs): - context = super(VersionDetailView, self).get_context_data(**kwargs) - version = self.get_data() - - table = project_tables.FunctionVersionsTable(self.request) - context["version"] = version - context["url"] = self.get_redirect_url() - context["actions"] = table.render_row_actions(version) - context["table_id"] = "function_version" - context["object_id"] = version.version_number - return context - - def get_tabs(self, request, *args, **kwargs): - version = self.get_data() - return self.tab_group_class(request, - version=version, - **kwargs) - - -def download_function(request, function_id): - try: - data = api.qinling.function_download(request, function_id) - - output = io.BytesIO() - for chunk in data: - output.write(chunk) - ctx = output.getvalue() - - response = HttpResponse(ctx, content_type='application/octet-stream') - response['Content-Length'] = str(len(response.content)) - - response['Content-Disposition'] = \ - 'attachment; filename=qinling-function-' + function_id + '.zip' - return response - except q_exc.NOT_FOUND as ne: - messages.error(request, - _('Error because file not found function: %s') % ne) - except Exception as e: - messages.error(request, _('Error downloading function: %s') % e) - return shortcuts.redirect(request.build_absolute_uri()) diff --git a/qinling_dashboard/content/runtimes/__init__.py b/qinling_dashboard/content/runtimes/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qinling_dashboard/content/runtimes/forms.py b/qinling_dashboard/content/runtimes/forms.py deleted file mode 100644 index 4b053e6..0000000 --- a/qinling_dashboard/content/runtimes/forms.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2012 Nebula, 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. - -from django.urls import reverse - -from django.utils.translation import ugettext_lazy as _ - -from horizon import exceptions -from horizon import forms -from horizon import messages - -from qinling_dashboard import api - -# from qinling_dashboard.utils import calculate_md5 - -from qinling_dashboard import validators - - -class CreateRuntimeForm(forms.SelfHandlingForm): - - image = forms.CharField(max_length=255, - label=_("Image"), - validators=[validators.validate_one_line_string], - required=True) - - name = forms.CharField(max_length=255, - label=_("Name"), - validators=[validators.validate_one_line_string], - required=False) - - description = forms.CharField( - max_length=255, - widget=forms.Textarea( - attrs={'class': 'modal-body-fixed-width', - 'rows': 3}), - label=_("Description"), - required=False) - - untrusted = forms.BooleanField( - label=_("Create as Untrusted Image"), - required=False, - help_text=_("Check this item if you would like to " - "create untrusted runtime"), - initial=False - ) - - def __init__(self, request, *args, **kwargs): - super(CreateRuntimeForm, self).__init__(request, *args, **kwargs) - - def handle(self, request, context): - params = {} - - # basic parameters - params.update({'image': context.get('image')}) - - if context.get('name'): - params.update({'name': context.get('name')}) - - if context.get('description'): - params.update({'description': context.get('description')}) - - if context.get('untrusted'): - trusted = not bool(context.get('untrusted')) - params.update({'trusted': trusted}) - - try: - api.qinling.runtime_create(request, **params) - message = _('Created runtime "%s"') % params.get('name', - 'unknown name') - messages.success(request, message) - return True - except Exception: - redirect = reverse("horizon:project:runtimes:index") - exceptions.handle(request, - _("Unable to create runtime."), - redirect=redirect) diff --git a/qinling_dashboard/content/runtimes/panel.py b/qinling_dashboard/content/runtimes/panel.py deleted file mode 100644 index 42cc0af..0000000 --- a/qinling_dashboard/content/runtimes/panel.py +++ /dev/null @@ -1,22 +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. - -from django.utils.translation import ugettext_lazy as _ - -import horizon - - -class Runtimes(horizon.Panel): - name = _("Runtimes") - slug = "runtimes" - permissions = ('openstack.services.function-engine',) diff --git a/qinling_dashboard/content/runtimes/tables.py b/qinling_dashboard/content/runtimes/tables.py deleted file mode 100644 index 97cbcbc..0000000 --- a/qinling_dashboard/content/runtimes/tables.py +++ /dev/null @@ -1,92 +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. - - -from django.utils.translation import ugettext_lazy as _ - -from horizon import tables - -from qinling_dashboard import api -from qinling_dashboard import utils - - -class CreateRuntime(tables.LinkAction): - name = "create" - verbose_name = _("Create Runtime") - url = "horizon:project:runtimes:create" - classes = ("ajax-modal", "btn-create") - policy_rules = (("function_engine", "runtime:create"),) - icon = "plus" - ajax = True - - -class RuntimesFilterAction(tables.FilterAction): - - def filter(self, table, runtimes, filter_string): - """Naive case-insensitive search.""" - q = filter_string.lower() - return [runtime for runtime in runtimes - if q in runtime.name.lower()] - - -class UpdateRow(tables.Row): - ajax = True - - def get_data(self, request, runtime_id): - execution = api.qinling.runtime_get(request, runtime_id) - return execution - - -class RuntimesTable(tables.DataTable): - - id = tables.Column("id", - verbose_name=_("Id"), - link="horizon:project:runtimes:detail") - - name = tables.Column("name", - verbose_name=_("Name")) - - image = tables.Column("image", - verbose_name=_("Image")) - - created_at = tables.Column("created_at", - verbose_name=_("Created At")) - - updated_at = tables.Column("updated_at", - verbose_name=_("Updated At")) - - project_id = tables.Column("project_id", - verbose_name=_("Project ID")) - - is_public = tables.Column("is_public", - verbose_name=_("Is Public")) - - status = tables.Column( - "status", - status=True, - status_choices=utils.FUNCTION_ENGINE_STATUS_CHOICES, - display_choices=utils.FUNCTION_ENGINE_STATUS_DISPLAY_CHOICES) - - def __init__(self, request, data=None, needs_form_wrapper=None, **kwargs): - super(RuntimesTable, self).__init__(request, data, - needs_form_wrapper, **kwargs) - if not request.user.is_superuser: - del self.columns["is_public"] - - class Meta(object): - name = "runtimes" - verbose_name = _("Runtimes") - status_columns = ["status"] - multi_select = True - row_class = UpdateRow - table_actions = (CreateRuntime, - RuntimesFilterAction,) diff --git a/qinling_dashboard/content/runtimes/tabs.py b/qinling_dashboard/content/runtimes/tabs.py deleted file mode 100644 index af72a51..0000000 --- a/qinling_dashboard/content/runtimes/tabs.py +++ /dev/null @@ -1,37 +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 logging - -from django.utils.translation import ugettext_lazy as _ - -from horizon import tabs - - -LOG = logging.getLogger(__name__) - - -class RuntimeOverviewTab(tabs.Tab): - name = _("Overview") - slug = "overview" - template_name = "project/runtimes/_detail_overview.html" - - def get_context_data(self, request): - return {"runtime": self.tab_group.kwargs['runtime'], - "is_superuser": self.request.user.is_superuser} - - -class RuntimeDetailTabs(tabs.TabGroup): - slug = "runtime_details" - tabs = (RuntimeOverviewTab,) - sticky = True - show_single_tab = False diff --git a/qinling_dashboard/content/runtimes/templates/runtimes/_create.html b/qinling_dashboard/content/runtimes/templates/runtimes/_create.html deleted file mode 100644 index 58d7b02..0000000 --- a/qinling_dashboard/content/runtimes/templates/runtimes/_create.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} -{% block modal-body-right %} -

{% trans "Description:" %}

-

{% trans "Create a new runtime." %}

-{% endblock %} diff --git a/qinling_dashboard/content/runtimes/templates/runtimes/_detail_overview.html b/qinling_dashboard/content/runtimes/templates/runtimes/_detail_overview.html deleted file mode 100644 index 3af206b..0000000 --- a/qinling_dashboard/content/runtimes/templates/runtimes/_detail_overview.html +++ /dev/null @@ -1,38 +0,0 @@ -{% load i18n %} - -
-
- -
{% trans "ID" %}
-
{{ runtime.id }}
- -
{% trans "Name" %}
-
{{ runtime.name }}
- -
{% trans "Image" %}
-
{{ runtime.image }}
- -
{% trans "Description" %}
-
{{ runtime.description }}
- -
{% trans "Project ID" %}
-
{{ runtime.project_id }}
- -
{% trans "Created At" %}
-
{{ runtime.created_at|parse_isotime }}
- -
{% trans "Updated At" %}
-
{{ runtime.updated_at|parse_isotime }}
- - {% if is_superuser %} -
{% trans "Is Public" %}
-
{{ runtime.is_public|default:_("Unknown") }}
- {% endif %} - -
{% trans "Status" %}
- {% with runtime.status|title as rt_status %} -
{% trans rt_status context "current status of a runtime" %}
- {% endwith %} - -
-
diff --git a/qinling_dashboard/content/runtimes/templates/runtimes/create.html b/qinling_dashboard/content/runtimes/templates/runtimes/create.html deleted file mode 100644 index 9a9e3b5..0000000 --- a/qinling_dashboard/content/runtimes/templates/runtimes/create.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Create Runtime" %}{% endblock %} - -{% block main %} - {% include 'project/runtimes/_create.html' %} -{% endblock %} diff --git a/qinling_dashboard/content/runtimes/templates/runtimes/detail.html b/qinling_dashboard/content/runtimes/templates/runtimes/detail.html deleted file mode 100644 index bdb145a..0000000 --- a/qinling_dashboard/content/runtimes/templates/runtimes/detail.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Runtime Details" %}{% endblock %} - -{% block main %} -
-
- {{ tab_group.render }} -
-
-{% endblock %} diff --git a/qinling_dashboard/content/runtimes/urls.py b/qinling_dashboard/content/runtimes/urls.py deleted file mode 100644 index 9aba9ca..0000000 --- a/qinling_dashboard/content/runtimes/urls.py +++ /dev/null @@ -1,22 +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. - -from django.conf.urls import url - -from qinling_dashboard.content.runtimes import views - -urlpatterns = [ - url(r'^$', views.IndexView.as_view(), name='index'), - url(r'^(?P[^/]+)/$', - views.DetailView.as_view(), name='detail'), - url(r'^create', views.CreateRuntimeView.as_view(), name='create'), -] diff --git a/qinling_dashboard/content/runtimes/views.py b/qinling_dashboard/content/runtimes/views.py deleted file mode 100644 index 39adc7b..0000000 --- a/qinling_dashboard/content/runtimes/views.py +++ /dev/null @@ -1,94 +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. - -from django.urls import reverse -from django.urls import reverse_lazy -from django.utils.translation import ugettext_lazy as _ - -from horizon import exceptions -from horizon import forms -from horizon import tables -from horizon import tabs -from horizon.utils import memoized - -from qinling_dashboard import api -from qinling_dashboard.content.runtimes import forms as project_forms -from qinling_dashboard.content.runtimes import tables as project_tables -from qinling_dashboard.content.runtimes import tabs as project_tabs - - -class CreateRuntimeView(forms.ModalFormView): - - form_class = project_forms.CreateRuntimeForm - modal_header = submit_label = page_title = _("Create Runtime") - template_name = 'project/runtimes/create.html' - submit_url = reverse_lazy("horizon:project:runtimes:create") - success_url = reverse_lazy("horizon:project:runtimes:index") - - -class IndexView(tables.DataTableView): - - table_class = project_tables.RuntimesTable - page_title = _("Runtimes") - - def get_data(self): - try: - runtimes = api.qinling.runtimes_list(self.request) - except Exception: - runtimes = [] - msg = _('Unable to retrieve runtimes list.') - exceptions.handle(self.request, msg) - return runtimes - - -class DetailView(tabs.TabView): - tab_group_class = project_tabs.RuntimeDetailTabs - template_name = 'project/runtimes/detail.html' - page_title = _("Runtime Details: {{ resource_name }}") - failure_url = reverse_lazy('horizon:project:runtimes:index') - - @memoized.memoized_method - def get_data(self): - runtime_id = self.kwargs['runtime_id'] - try: - runtime = api.qinling.runtime_get(self.request, runtime_id) - except Exception: - exceptions.handle( - self.request, - _('Unable to retrieve ' - 'details for Runtime "%s".') % runtime_id, - redirect=self.failure_url - ) - return runtime - - def get_context_data(self, **kwargs): - context = super(DetailView, self).get_context_data(**kwargs) - runtime = self.get_data() - table = project_tables.RuntimesTable(self.request) - resource_name = runtime.name if runtime.name else runtime.id - context["runtime"] = runtime - context["url"] = self.get_redirect_url() - context["actions"] = table.render_row_actions(runtime) - context["table_id"] = "runtime" - context["resource_name"] = resource_name - context["object_id"] = runtime.id - return context - - def get_tabs(self, request, *args, **kwargs): - runtime = self.get_data() - return self.tab_group_class(request, - runtime=runtime, - **kwargs) - - @staticmethod - def get_redirect_url(): - return reverse('horizon:project:runtimes:index') diff --git a/qinling_dashboard/enabled/_7110_project_function_engine_panel.py b/qinling_dashboard/enabled/_7110_project_function_engine_panel.py deleted file mode 100644 index 2139c51..0000000 --- a/qinling_dashboard/enabled/_7110_project_function_engine_panel.py +++ /dev/null @@ -1,30 +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. - -from django.utils.translation import ugettext_lazy as _ - -from qinling_dashboard import exceptions - -# The slug of the panel group to be added to HORIZON_CONFIG. Required. -PANEL_GROUP = 'function_engine' -# The display name of the PANEL_GROUP. Required. -PANEL_GROUP_NAME = _('Function Engine') -# The slug of the dashboard the PANEL_GROUP associated with. Required. -PANEL_GROUP_DASHBOARD = 'project' - -ADD_INSTALLED_APPS = ["qinling_dashboard", ] - -ADD_EXCEPTIONS = { - 'not_found': exceptions.NOT_FOUND, - 'recoverable': exceptions.RECOVERABLE, - 'unauthorized': exceptions.UNAUTHORIZED -} diff --git a/qinling_dashboard/enabled/_7120_project_runtimes_panel.py b/qinling_dashboard/enabled/_7120_project_runtimes_panel.py deleted file mode 100644 index 59cdc64..0000000 --- a/qinling_dashboard/enabled/_7120_project_runtimes_panel.py +++ /dev/null @@ -1,24 +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. - -# The slug of the panel to be added to HORIZON_CONFIG. Required. -PANEL = 'runtimes' -# The slug of the dashboard the PANEL associated with. Required. -PANEL_DASHBOARD = 'project' -# The slug of the panel group the PANEL is associated with. -PANEL_GROUP = 'function_engine' - -# Python panel class of the PANEL to be added. -ADD_PANEL = 'qinling_dashboard.content.runtimes.panel.Runtimes' - -# Automatically discover static resources in installed apps -AUTO_DISCOVER_STATIC_FILES = True diff --git a/qinling_dashboard/enabled/_7130_project_functions_panel.py b/qinling_dashboard/enabled/_7130_project_functions_panel.py deleted file mode 100644 index bf92d77..0000000 --- a/qinling_dashboard/enabled/_7130_project_functions_panel.py +++ /dev/null @@ -1,24 +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. - -# The slug of the panel to be added to HORIZON_CONFIG. Required. -PANEL = 'functions' -# The slug of the dashboard the PANEL associated with. Required. -PANEL_DASHBOARD = 'project' -# The slug of the panel group the PANEL is associated with. -PANEL_GROUP = 'function_engine' - -# Python panel class of the PANEL to be added. -ADD_PANEL = 'qinling_dashboard.content.functions.panel.Functions' - -# Automatically discover static resources in installed apps -AUTO_DISCOVER_STATIC_FILES = True diff --git a/qinling_dashboard/enabled/_7140_project_executions_panel.py b/qinling_dashboard/enabled/_7140_project_executions_panel.py deleted file mode 100644 index 794347d..0000000 --- a/qinling_dashboard/enabled/_7140_project_executions_panel.py +++ /dev/null @@ -1,24 +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. - -# The slug of the panel to be added to HORIZON_CONFIG. Required. -PANEL = 'executions' -# The slug of the dashboard the PANEL associated with. Required. -PANEL_DASHBOARD = 'project' -# The slug of the panel group the PANEL is associated with. -PANEL_GROUP = 'function_engine' - -# Python panel class of the PANEL to be added. -ADD_PANEL = 'qinling_dashboard.content.executions.panel.Executions' - -# Automatically discover static resources in installed apps -AUTO_DISCOVER_STATIC_FILES = True diff --git a/qinling_dashboard/enabled/__init__.py b/qinling_dashboard/enabled/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qinling_dashboard/exceptions.py b/qinling_dashboard/exceptions.py deleted file mode 100644 index e6e4ef2..0000000 --- a/qinling_dashboard/exceptions.py +++ /dev/null @@ -1,28 +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. - -from qinlingclient.common import exceptions as exc - - -UNAUTHORIZED = ( - exc.Unauthorized, -) - - -NOT_FOUND = ( - exc.NotFound, -) - - -RECOVERABLE = ( - exc.HTTPException, -) diff --git a/qinling_dashboard/locale/en_GB/LC_MESSAGES/django.po b/qinling_dashboard/locale/en_GB/LC_MESSAGES/django.po deleted file mode 100644 index 153c317..0000000 --- a/qinling_dashboard/locale/en_GB/LC_MESSAGES/django.po +++ /dev/null @@ -1,462 +0,0 @@ -# Andi Chandler , 2018. #zanata -# Andi Chandler , 2020. #zanata -msgid "" -msgstr "" -"Project-Id-Version: qinling-dashboard VERSION\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2020-09-11 21:48+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2020-06-15 05:40+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en_GB\n" -"X-Generator: Zanata 4.3.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "1st character is not valid." -msgstr "1st character is not valid." - -msgctxt "current status of runtime" -msgid "Available" -msgstr "Available" - -msgid "CPU" -msgstr "CPU" - -msgid "CPU (Milli CPU)" -msgstr "CPU (Milli CPU)" - -msgid "CPU (Milli CPU)" -msgstr "CPU (Milli CPU)" - -msgctxt "current status of runtime" -msgid "Cancelled" -msgstr "Cancelled" - -msgid "Check this item if you would like sync execution." -msgstr "Check this item if you would like sync execution." - -msgid "Check this item if you would like to create untrusted runtime" -msgstr "Check this item if you would like to create untrusted runtime" - -msgid "Code" -msgstr "Code" - -msgid "Code Type" -msgstr "Code Type" - -msgid "Code Type can not be changed when you update function." -msgstr "Code Type can not be changed when you update function." - -msgid "Code package zip file path." -msgstr "Code package zip file path." - -msgid "Container name in Swift." -msgstr "Container name in Swift." - -msgid "Count" -msgstr "Count" - -msgid "Create Execution" -msgstr "Create Execution" - -msgid "Create Function" -msgstr "Create Function" - -msgid "Create Function Version" -msgstr "Create Function Version" - -msgid "Create Runtime" -msgstr "Create Runtime" - -msgid "Create Version" -msgstr "Create Version" - -msgid "Create a new execution of function." -msgstr "Create a new execution of function." - -msgid "Create a new function." -msgstr "Create a new function." - -msgid "Create a new runtime." -msgstr "Create a new runtime." - -msgid "Create a new version of function." -msgstr "Create a new version of function." - -msgid "Create as Untrusted Image" -msgstr "Create as Untrusted Image" - -msgid "Created At" -msgstr "Created At" - -#, python-format -msgid "Created execution of \"%s\"" -msgstr "Created execution of \"%s\"" - -#, python-format -msgid "Created function \"%s\"" -msgstr "Created function \"%s\"" - -#, python-format -msgid "Created new version of \"%s\"" -msgstr "Created new version of \"%s\"" - -#, python-format -msgid "Created runtime \"%s\"" -msgstr "Created runtime \"%s\"" - -msgctxt "current status of runtime" -msgid "Creating" -msgstr "Creating" - -msgid "Delete Execution" -msgid_plural "Delete Executions" -msgstr[0] "Delete Execution" -msgstr[1] "Delete Executions" - -msgid "Delete Function" -msgid_plural "Delete Functions" -msgstr[0] "Delete Function" -msgstr[1] "Delete Functions" - -msgid "Delete Function Version" -msgid_plural "Delete Function Versions" -msgstr[0] "Delete Function Version" -msgstr[1] "Delete Function Versions" - -msgid "Deleted executions are not recoverable." -msgstr "Deleted executions are not recoverable." - -msgid "Deleted function versions are not recoverable." -msgstr "Deleted function versions are not recoverable." - -msgid "Deleted functions are not recoverable." -msgstr "Deleted functions are not recoverable." - -msgctxt "current status of runtime" -msgid "Deleting" -msgstr "Deleting" - -msgid "Description" -msgstr "Description" - -msgid "Description:" -msgstr "Description:" - -msgctxt "current status of runtime" -msgid "Done" -msgstr "Done" - -msgid "Download Function" -msgstr "Download Function" - -msgid "Duration" -msgstr "Duration" - -msgid "Entry" -msgstr "Entry" - -msgctxt "current status of runtime" -msgid "Error" -msgstr "Error" - -#, python-format -msgid "Error because file not found function: %s" -msgstr "Error because file not found function: %s" - -#, python-format -msgid "Error downloading function: %s" -msgstr "Error downloading function: %s" - -msgid "Execution Details" -msgstr "Execution Details" - -msgid "Execution Details: {{ resource_name }}" -msgstr "Execution Details: {{ resource_name }}" - -msgid "Execution Logs" -msgstr "Execution Logs" - -msgid "Executions" -msgstr "Executions" - -msgid "Executions of this function" -msgstr "Executions of this function" - -msgctxt "current status of runtime" -msgid "Failed" -msgstr "Failed" - -msgid "Function" -msgstr "Function" - -msgid "Function Details" -msgstr "Function Details" - -msgid "Function Details: {{ resource_name }}" -msgstr "Function Details: {{ resource_name }}" - -msgid "Function Engine" -msgstr "Function Engine" - -msgid "Function ID" -msgstr "Function ID" - -msgid "Function Version" -msgstr "Function Version" - -msgid "Function Version Details" -msgstr "Function Version Details" - -msgid "" -"Function Version Details: {{ version.function_id }} (Version " -"Number={{ version_number }})" -msgstr "" -"Function Version Details: {{ version.function_id }} (Version " -"Number={{ version_number }})" - -msgid "Function entry in the format of ." -msgstr "Function entry in the format of ." - -msgid "Function to execute." -msgstr "Function to execute." - -msgid "Function which new version will be created." -msgstr "Function which new version will be created." - -msgid "Functions" -msgstr "Functions" - -msgid "ID" -msgstr "ID" - -msgid "Id" -msgstr "Id" - -msgid "Image" -msgstr "Image" - -msgid "Image name in Docker hub." -msgstr "Image name in Docker hub." - -msgid "Input" -msgstr "Input" - -msgid "Invalid character is used or exceeding maximum length." -msgstr "Invalid character is used or exceeding maximum length." - -msgid "Is Public" -msgstr "Is Public" - -msgid "Last character is not valid." -msgstr "Last character is not valid." - -msgid "Limit of cpu resource(unit: millicpu). Range: {0} ~ {1}" -msgstr "Limit of CPU resource(unit: millicpu). Range: {0} ~ {1}" - -msgid "Limit of memory resource(unit: bytes). Range: {0} ~ {1} (bytes)." -msgstr "Limit of memory resource(unit: bytes). Range: {0} ~ {1} (bytes)." - -msgid "Md5sum" -msgstr "MD5sum" - -msgid "Memory Size" -msgstr "Memory Size" - -msgid "Memory Size (Bytes)" -msgstr "Memory Size (Bytes)" - -msgid "Name" -msgstr "Name" - -msgid "No functions available." -msgstr "No functions available." - -msgid "No runtimes found" -msgstr "No runtimes found" - -msgid "Not key-value pair." -msgstr "Not key-value pair." - -msgid "Object name in Swift." -msgstr "Object name in Swift." - -msgid "Output" -msgstr "Output" - -msgid "Overview" -msgstr "Overview" - -msgid "Package" -msgstr "Package" - -msgctxt "current status of runtime" -msgid "Paused" -msgstr "Paused" - -msgid "Project ID" -msgstr "Project ID" - -msgid "Result" -msgstr "Result" - -msgctxt "current status of runtime" -msgid "Running" -msgstr "Running" - -msgid "Runtime" -msgstr "Runtime" - -msgid "Runtime Details" -msgstr "Runtime Details" - -msgid "Runtime Details: {{ resource_name }}" -msgstr "Runtime Details: {{ resource_name }}" - -msgid "Runtime ID" -msgstr "Runtime ID" - -msgid "Runtimes" -msgstr "Runtimes" - -msgid "Select Your Code Type." -msgstr "Select Your Code Type." - -msgid "Show Execution Logs" -msgstr "Show Execution Logs" - -msgid "Source" -msgstr "Source" - -msgid "" -"Specify input parmeters like name1=value2. One line is equivalent of one " -"input parameter." -msgstr "" -"Specify input parameters like name1=value2. One line is equivalent of one " -"input parameter." - -msgid "Status" -msgstr "Status" - -msgctxt "current status of runtime" -msgid "Success" -msgstr "Success" - -msgid "Swift Container" -msgstr "Swift Container" - -msgid "Swift Object" -msgstr "Swift Object" - -msgid "Sync" -msgstr "Sync" - -#, python-format -msgid "This function does not have specified version number: %s" -msgstr "This function does not have specified version number: %s" - -msgid "Unable to create function." -msgstr "Unable to create function." - -msgid "Unable to create runtime." -msgstr "Unable to create runtime." - -#, python-format -msgid "Unable to get executions of this function \"%s\"." -msgstr "Unable to get executions of this function \"%s\"." - -#, python-format -msgid "Unable to get versions of this function \"%s\"." -msgstr "Unable to get versions of this function \"%s\"." - -#, python-format -msgid "Unable to load the specified function. %s" -msgstr "Unable to load the specified function. %s" - -#, python-format -msgid "Unable to retrieve details for Function \"%s\"." -msgstr "Unable to retrieve details for Function \"%s\"." - -#, python-format -msgid "Unable to retrieve details for Runtime \"%s\"." -msgstr "Unable to retrieve details for Runtime \"%s\"." - -#, python-format -msgid "Unable to retrieve details for execution \"%s\"." -msgstr "Unable to retrieve details for execution \"%s\"." - -#, python-format -msgid "Unable to retrieve details for function version \"%s\"." -msgstr "Unable to retrieve details for function version \"%s\"." - -msgid "Unable to retrieve execution logs." -msgstr "Unable to retrieve execution logs." - -msgid "Unable to retrieve executions list." -msgstr "Unable to retrieve executions list." - -msgid "Unable to retrieve function details." -msgstr "Unable to retrieve function details." - -msgid "Unable to retrieve functions list." -msgstr "Unable to retrieve functions list." - -msgid "Unable to retrieve runtimes list." -msgstr "Unable to retrieve runtimes list." - -msgid "Unable to retrieve runtimes." -msgstr "Unable to retrieve runtimes." - -#, python-format -msgid "Unable to update function %s" -msgstr "Unable to update function %s" - -msgid "Unknown" -msgstr "Unknown" - -msgid "Update Function" -msgstr "Update Function" - -msgid "Update function." -msgstr "Update function." - -msgid "Updated At" -msgstr "Updated At" - -#, python-format -msgid "Updated function \"%s\"" -msgstr "Updated function \"%s\"" - -msgctxt "current status of runtime" -msgid "Upgrading" -msgstr "Upgrading" - -msgid "Version" -msgstr "Version" - -msgid "Version Number" -msgstr "Version Number" - -msgid "Version detail" -msgstr "Version detail" - -msgid "Versions" -msgstr "Versions" - -msgid "Versions of this function" -msgstr "Versions of this function" - -msgid "You must specify Docker image." -msgstr "You must specify Docker image." - -msgid "You must specify container and object both in case code type is Swift." -msgstr "You must specify container and object both in case code type is Swift." - -msgid "You must specify package file." -msgstr "You must specify package file." - -msgid "You must specify runtime." -msgstr "You must specify runtime." diff --git a/qinling_dashboard/locale/ko_KR/LC_MESSAGES/django.po b/qinling_dashboard/locale/ko_KR/LC_MESSAGES/django.po deleted file mode 100644 index cc7ab69..0000000 --- a/qinling_dashboard/locale/ko_KR/LC_MESSAGES/django.po +++ /dev/null @@ -1,466 +0,0 @@ -# ByungYeol Woo , 2018. #zanata -# SEEUNG KANG , 2018. #zanata -# Hongjae Kim , 2019. #zanata -msgid "" -msgstr "" -"Project-Id-Version: qinling-dashboard VERSION\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2020-09-11 21:48+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2019-11-02 09:02+0000\n" -"Last-Translator: Hongjae Kim \n" -"Language-Team: Korean (South Korea)\n" -"Language: ko_KR\n" -"X-Generator: Zanata 4.3.3\n" -"Plural-Forms: nplurals=1; plural=0\n" - -msgid "1st character is not valid." -msgstr "첫번째 문자가 올바르지 않습니다." - -msgctxt "current status of runtime" -msgid "Available" -msgstr "사용 가능" - -msgid "CPU" -msgstr "CPU" - -msgid "CPU (Milli CPU)" -msgstr "CPU (Milli CPU)" - -msgid "CPU (Milli CPU)" -msgstr "CPU (Milli CPU)" - -msgctxt "current status of runtime" -msgid "Cancelled" -msgstr "취소됨" - -msgid "Check this item if you would like sync execution." -msgstr "싱크 실행을 하려면 이 항목을 확인하세요." - -msgid "Check this item if you would like to create untrusted runtime" -msgstr "신뢰할 수 없는 런타임을 생성하려면 이 항목을 선택하십시오." - -msgid "Code" -msgstr "코드" - -msgid "Code Type" -msgstr "코드 타입" - -msgid "Code Type can not be changed when you update function." -msgstr "기능을 업데이트하면 코드 타입을 바꿀 수 없습니다." - -msgid "Code package zip file path." -msgstr "코드 패키지 압축 파일 경로" - -msgid "Container name in Swift." -msgstr "Swift에서의 컨테이너 이름" - -msgid "Count" -msgstr "개수" - -msgid "Create Execution" -msgstr "실행 생성" - -msgid "Create Function" -msgstr "기능 생성" - -msgid "Create Function Version" -msgstr "기능 버전 생성" - -msgid "Create Runtime" -msgstr "런타임 만들기" - -msgid "Create Version" -msgstr "버전 생성" - -msgid "Create a new execution of function." -msgstr "새로운 기능의 실행 생성" - -msgid "Create a new function." -msgstr "새로운 기능 생성" - -msgid "Create a new runtime." -msgstr "새 런타임을 생성하십시오." - -msgid "Create a new version of function." -msgstr "새로운 버전의 기능 생성" - -msgid "Create as Untrusted Image" -msgstr "신뢰할 수 없는 이미지로 만들기" - -msgid "Created At" -msgstr "생성 시점" - -#, python-format -msgid "Created execution of \"%s\"" -msgstr "\"%s\"을 실행 생성" - -#, python-format -msgid "Created function \"%s\"" -msgstr "기능 생성 \"%s\"" - -#, python-format -msgid "Created new version of \"%s\"" -msgstr "새로운 버전\"%s\" 생성" - -#, python-format -msgid "Created runtime \"%s\"" -msgstr "%s 런타임 생성" - -msgctxt "current status of runtime" -msgid "Creating" -msgstr "생성 중" - -msgid "Delete Execution" -msgid_plural "Delete Executions" -msgstr[0] "" -"실행 삭제\n" -"실행 삭제" - -msgid "Delete Function" -msgid_plural "Delete Functions" -msgstr[0] "" -"기능 삭제\n" -"기능들 삭제" - -msgid "Delete Function Version" -msgid_plural "Delete Function Versions" -msgstr[0] "" -"삭제된 기능 버전\n" -"삭제된 기능 버전들" - -msgid "Deleted executions are not recoverable." -msgstr "삭제된 실행은 되살릴 수 없습니다." - -msgid "Deleted function versions are not recoverable." -msgstr "삭제된 기능 버전은 되살릴 수 없습니다." - -msgid "Deleted functions are not recoverable." -msgstr "삭제된 기능은 되살릴 수 없습니다." - -msgctxt "current status of runtime" -msgid "Deleting" -msgstr "삭제 중" - -msgid "Description" -msgstr "설명" - -msgid "Description:" -msgstr "설명:" - -msgctxt "current status of runtime" -msgid "Done" -msgstr "완료" - -msgid "Download Function" -msgstr "기능 다운로드" - -msgid "Duration" -msgstr "기간" - -msgid "Entry" -msgstr "진입점" - -msgctxt "current status of runtime" -msgid "Error" -msgstr "오류" - -#, python-format -msgid "Error because file not found function: %s" -msgstr "파일이 발견되지 않은 오류:%s" - -#, python-format -msgid "Error downloading function: %s" -msgstr "기능 다운로드 오류:%s" - -msgid "Execution Details" -msgstr "운영 정보" - -msgid "Execution Details: {{ resource_name }}" -msgstr "실행 정보: {{ resource_name }}" - -msgid "Execution Logs" -msgstr "운영 로그" - -msgid "Executions" -msgstr "실행" - -msgid "Executions of this function" -msgstr "이 기능을 실행" - -msgctxt "current status of runtime" -msgid "Failed" -msgstr "실패함" - -msgid "Function" -msgstr "기능" - -msgid "Function Details" -msgstr "기능 세부사항" - -msgid "Function Details: {{ resource_name }}" -msgstr "기능 세부사항:{{ resource_name }}" - -msgid "Function Engine" -msgstr "기능 엔진" - -msgid "Function ID" -msgstr "기능 ID" - -msgid "Function Version" -msgstr "기능 버전" - -msgid "Function Version Details" -msgstr "기능 버전 세부사항" - -msgid "" -"Function Version Details: {{ version.function_id }} (Version " -"Number={{ version_number }})" -msgstr "" -"기능 버전 세부사항: {{ version.function_id }} (Version " -"Number={{ version_number }})" - -msgid "Function entry in the format of ." -msgstr "기능 진입점 형태는 . " - -msgid "Function to execute." -msgstr "실행할 기능" - -msgid "Function which new version will be created." -msgstr "새로운 버전이 생성될 기능" - -msgid "Functions" -msgstr "기능" - -msgid "ID" -msgstr "ID" - -msgid "Id" -msgstr "ID" - -msgid "Image" -msgstr "이미지" - -msgid "Image name in Docker hub." -msgstr "도커 허브에서의 이미지 이름" - -msgid "Input" -msgstr "입력" - -msgid "Invalid character is used or exceeding maximum length." -msgstr "올바르지 않은 문자가 사용되거나 길이가 최대값보다 큽니다." - -msgid "Is Public" -msgstr "공개 여부" - -msgid "Last character is not valid." -msgstr "마지막 문자가 올바르지 않습니다." - -msgid "Limit of cpu resource(unit: millicpu). Range: {0} ~ {1}" -msgstr "CPU 자원 제한(단위: millicpu). 범위: {0} ~ {1}" - -msgid "Limit of memory resource(unit: bytes). Range: {0} ~ {1} (bytes)." -msgstr "메모리 자원 제한(단위: bytes). 범위: {0} ~ {1} (bytes)." - -msgid "Md5sum" -msgstr "Md5sum" - -msgid "Memory Size" -msgstr "메모리 크기" - -msgid "Memory Size (Bytes)" -msgstr "메모리 크기(Bytes)" - -msgid "Name" -msgstr "이름" - -msgid "No functions available." -msgstr "사용 가능한 기능이 없습니다." - -msgid "No runtimes found" -msgstr "런타임을 찾지 못했습니다." - -msgid "Not key-value pair." -msgstr "키값이 맞지 않습니다." - -msgid "Object name in Swift." -msgstr "Swift에서의 오브젝트 이름" - -msgid "Output" -msgstr "출력" - -msgid "Overview" -msgstr "개요" - -msgid "Package" -msgstr "패키지" - -msgctxt "current status of runtime" -msgid "Paused" -msgstr "정지함" - -msgid "Project ID" -msgstr "프로젝트 ID" - -msgid "Result" -msgstr "결과" - -msgctxt "current status of runtime" -msgid "Running" -msgstr "실행중" - -msgid "Runtime" -msgstr "런타임" - -msgid "Runtime Details" -msgstr "런타임 세부사항" - -msgid "Runtime Details: {{ resource_name }}" -msgstr "런타임 세부사항: {{ resource_name }}" - -msgid "Runtime ID" -msgstr "런타임 ID" - -msgid "Runtimes" -msgstr "런타임" - -msgid "Select Your Code Type." -msgstr "코드 타입을 선택하세요." - -msgid "Show Execution Logs" -msgstr "운영 로그를 나타냄" - -msgid "Source" -msgstr "소스" - -msgid "" -"Specify input parmeters like name1=value2. One line is equivalent of one " -"input parameter." -msgstr "" -"name1=value2처럼 입력 매개변수를 지정하시오. 한 줄이 하나의 매개변수와 같습" -"니다." - -msgid "Status" -msgstr "상태" - -msgctxt "current status of runtime" -msgid "Success" -msgstr "완료" - -msgid "Swift Container" -msgstr "Swift 컨테이너" - -msgid "Swift Object" -msgstr "Swift 오브젝트" - -msgid "Sync" -msgstr "싱크" - -#, python-format -msgid "This function does not have specified version number: %s" -msgstr "이 기능은 지정된 버전 숫자가 없습니다:%s" - -msgid "Unable to create function." -msgstr "기능을 생성하는데 실패하였습니다." - -msgid "Unable to create runtime." -msgstr "런타임을 생성할 수 없음." - -#, python-format -msgid "Unable to get executions of this function \"%s\"." -msgstr "기능 \"%s\"의 실행을 가져오지 못했습니다." - -#, python-format -msgid "Unable to get versions of this function \"%s\"." -msgstr "기능 \"%s\"의 버전을 가져오지 못했습니다." - -#, python-format -msgid "Unable to load the specified function. %s" -msgstr "지정된 기능을 불러올 수 없습니다.%s" - -#, python-format -msgid "Unable to retrieve details for Function \"%s\"." -msgstr "기능 \"%s\"의 세부사항을 가져오지 못했습니다." - -#, python-format -msgid "Unable to retrieve details for Runtime \"%s\"." -msgstr "런타임 \"%s\"에 대한 세부사항을 가져오지 못했습니다." - -#, python-format -msgid "Unable to retrieve details for execution \"%s\"." -msgstr "\"%s\" 실행에 대한 정보를 찾을 수 없습니다." - -#, python-format -msgid "Unable to retrieve details for function version \"%s\"." -msgstr "기능 버전\"%s\"의 세부사항을 가져오지 못했습니다." - -msgid "Unable to retrieve execution logs." -msgstr "실행 로그를 찾아올 수 없습니다." - -msgid "Unable to retrieve executions list." -msgstr "실행 목록을 찾을 수 없습니다." - -msgid "Unable to retrieve function details." -msgstr "기능 세부사항을 가져오지 못했습니다." - -msgid "Unable to retrieve functions list." -msgstr "기능 리스트를 가져오지 못했습니다." - -msgid "Unable to retrieve runtimes list." -msgstr "런타임 리스트를 가져오지 못했습니다." - -msgid "Unable to retrieve runtimes." -msgstr "런타임을 가져오지 못했습니다." - -#, python-format -msgid "Unable to update function %s" -msgstr "기능 갱신 실패 \"%s\"" - -msgid "Unknown" -msgstr "알 수 없음" - -msgid "Update Function" -msgstr "기능 갱신" - -msgid "Update function." -msgstr "기능 갱신" - -msgid "Updated At" -msgstr "갱신 시점" - -#, python-format -msgid "Updated function \"%s\"" -msgstr "갱신된 기능 \"%s\"" - -msgctxt "current status of runtime" -msgid "Upgrading" -msgstr "업그레이드하는 중" - -msgid "Version" -msgstr "버전" - -msgid "Version Number" -msgstr "버전 번호" - -msgid "Version detail" -msgstr "버전 세부사항" - -msgid "Versions" -msgstr "버전" - -msgid "Versions of this function" -msgstr "이 기능의 버전" - -msgid "You must specify Docker image." -msgstr "Docker 이미지를 지정해야 합니다." - -msgid "You must specify container and object both in case code type is Swift." -msgstr "코드 타입이 Swift인 경우에 컨테이너와 오브젝트를 지정해야 합니다." - -msgid "You must specify package file." -msgstr "패키지 파일을 지정해야 합니다." - -msgid "You must specify runtime." -msgstr "런타임을 지정해야 합니다." diff --git a/qinling_dashboard/test/__init__.py b/qinling_dashboard/test/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qinling_dashboard/test/helpers.py b/qinling_dashboard/test/helpers.py deleted file mode 100644 index 7826efa..0000000 --- a/qinling_dashboard/test/helpers.py +++ /dev/null @@ -1,412 +0,0 @@ -# Copyright 2012 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# Copyright 2012 Nebula, 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. - -from functools import wraps -from importlib import import_module -import logging -import traceback -from unittest import mock - -from django.conf import settings -from django.contrib.messages.storage import default_storage -from django.test.client import RequestFactory -from django.utils import http -from horizon.test import helpers as horizon_helpers -from openstack_auth import user -from openstack_auth import utils -from openstack_dashboard import context_processors -from requests.packages.urllib3.connection import HTTPConnection - -from qinling_dashboard.test.test_data import utils as test_utils - -LOG = logging.getLogger(__name__) - -# Shortcuts to avoid importing horizon_helpers and for backward compatibility. -update_settings = horizon_helpers.update_settings -IsA = horizon_helpers.IsA -IsHttpRequest = horizon_helpers.IsHttpRequest - - -def create_mocks(target_methods): - """decorator to simplify setting up multiple mocks at once - - :param target_methods: a dict to define methods to be patched using mock. - - A key of "target_methods" is a target object whose attribute(s) are - patched. - - A value of "target_methods" is a list of methods to be patched - using mock. Each element of the list can be a string or a tuple - consisting of two strings. - - A string specifies a method name of "target" object to be mocked. - The decorator create a mock object for the method and the started mock - can be accessed via 'mock_' of the test class. - For example, in case of:: - - @create_mocks({api.nova: ['server_list', - 'flavor_list']}) - def test_example(self): - ... - self.mock_server_list.return_value = ... - self.mock_flavar_list.side_effect = ... - - you can access the mocked method via "self.mock_server_list" - inside a test class. - - The tuple version is useful when there are multiple methods with - a same name are mocked in a single test. - The format of the tuple is:: - - ("", "") - - The decorator create a mock object for "" - and the started mock can be accessed via 'mock_' of - the test class. - - Example:: - - @create_mocks({ - api.nova: [ - 'usage_get', - ('tenant_absolute_limits', 'nova_tenant_absolute_limits'), - 'extension_supported', - ], - api.cinder: [ - ('tenant_absolute_limits', 'cinder_tenant_absolute_limits'), - ], - }) - def test_example(self): - ... - self.mock_usage_get.return_value = ... - self.mock_nova_tenant_absolute_limits.return_value = ... - self.mock_cinder_tenant_absolute_limits.return_value = ... - ... - self.mock_extension_supported.assert_has_calls(....) - - """ - def wrapper(function): - @wraps(function) - def wrapped(inst, *args, **kwargs): - for target, methods in target_methods.items(): - for method in methods: - if isinstance(method, str): - method_mocked = method - attr_name = method - else: - method_mocked = method[0] - attr_name = method[1] - m = mock.patch.object(target, method_mocked) - setattr(inst, 'mock_%s' % attr_name, m.start()) - return function(inst, *args, **kwargs) - return wrapped - return wrapper - - -def _apply_panel_mocks(patchers=None): - """Global mocks on panels that get called on all views.""" - if patchers is None: - patchers = {} - mocked_methods = getattr(settings, 'TEST_GLOBAL_MOCKS_ON_PANELS', {}) - for name, mock_config in mocked_methods.items(): - method = mock_config['method'] - mock_params = {} - for param in ['return_value', 'side_effect']: - if param in mock_config: - mock_params[param] = mock_config[param] - patcher = mock.patch(method, **mock_params) - patcher.start() - patchers[name] = patcher - return patchers - - -class RequestFactoryWithMessages(RequestFactory): - def get(self, *args, **kwargs): - req = super(RequestFactoryWithMessages, self).get(*args, **kwargs) - req.user = utils.get_user(req) - req.session = [] - req._messages = default_storage(req) - return req - - def post(self, *args, **kwargs): - req = super(RequestFactoryWithMessages, self).post(*args, **kwargs) - req.user = utils.get_user(req) - req.session = [] - req._messages = default_storage(req) - return req - - -class TestCase(horizon_helpers.TestCase): - """Specialized base test case class for Horizon. - - It gives access to numerous additional features: - - * A full suite of test data through various attached objects and - managers (e.g. ``self.servers``, ``self.user``, etc.). See the - docs for - :class:`~openstack_dashboard.test.test_data.utils.TestData` - for more information. - * A set of request context data via ``self.context``. - * A ``RequestFactory`` class which supports Django's ``contrib.messages`` - framework via ``self.factory``. - * A ready-to-go request object via ``self.request``. - * The ability to override specific time data controls for easier testing. - * Several handy additional assertion methods. - """ - - # To force test failures when unmocked API calls are attempted, provide - # boolean variable to store failures - missing_mocks = False - - def fake_conn_request(self): - # print a stacktrace to illustrate where the unmocked API call - # is being made from - traceback.print_stack() - # forcing a test failure for missing mock - self.missing_mocks = True - - def setUp(self): - self._real_conn_request = HTTPConnection.connect - HTTPConnection.connect = self.fake_conn_request - - self._real_context_processor = context_processors.openstack - context_processors.openstack = lambda request: self.context - - self.patchers = _apply_panel_mocks() - - super(TestCase, self).setUp() - - def _setup_test_data(self): - super(TestCase, self)._setup_test_data() - test_utils.load_test_data(self) - self.context = { - 'authorized_tenants': self.tenants.list(), - 'JS_CATALOG': context_processors.get_js_catalog(settings), - } - - def _setup_factory(self): - # For some magical reason we need a copy of this here. - self.factory = RequestFactoryWithMessages() - - def _setup_user(self, **kwargs): - self._real_get_user = utils.get_user - tenants = self.context['authorized_tenants'] - base_kwargs = { - 'id': self.user.id, - 'token': self.token, - 'username': self.user.name, - 'domain_id': self.domain.id, - 'user_domain_name': self.domain.name, - 'tenant_id': self.tenant.id, - 'service_catalog': self.service_catalog, - 'authorized_tenants': tenants - } - base_kwargs.update(kwargs) - self.setActiveUser(**base_kwargs) - - def _setup_request(self): - super(TestCase, self)._setup_request() - self.request.session['token'] = self.token.id - - def tearDown(self): - HTTPConnection.connect = self._real_conn_request - context_processors.openstack = self._real_context_processor - utils.get_user = self._real_get_user - mock.patch.stopall() - super(TestCase, self).tearDown() - - # cause a test failure if an unmocked API call was attempted - if self.missing_mocks: - raise AssertionError("An unmocked API call was made.") - - def setActiveUser(self, id=None, token=None, username=None, tenant_id=None, - service_catalog=None, tenant_name=None, roles=None, - authorized_tenants=None, enabled=True, domain_id=None, - user_domain_name=None): - def get_user(request): - return user.User(id=id, - token=token, - user=username, - domain_id=domain_id, - user_domain_name=user_domain_name, - tenant_id=tenant_id, - tenant_name=tenant_name, - service_catalog=service_catalog, - roles=roles, - enabled=enabled, - authorized_tenants=authorized_tenants, - endpoint=settings.OPENSTACK_KEYSTONE_URL) - utils.get_user = get_user - - def assertRedirectsNoFollow(self, response, expected_url): - """Check for redirect. - - Asserts that the given response issued a 302 redirect without - processing the view which is redirected to. - """ - loc = str(response._headers.get('location', None)[1]) - loc = http.urlunquote(loc) - expected_url = http.urlunquote(expected_url) - self.assertEqual(loc, expected_url) - self.assertEqual(response.status_code, 302) - - def assertNoFormErrors(self, response, context_name="form"): - """Checks for no form errors. - - Asserts that the response either does not contain a form in its - context, or that if it does, that form has no errors. - """ - context = getattr(response, "context", {}) - if not context or context_name not in context: - return True - errors = response.context[context_name]._errors - assert len(errors) == 0, \ - "Unexpected errors were found on the form: %s" % errors - - def assertFormErrors(self, response, count=0, message=None, - context_name="form"): - """Check for form errors. - - Asserts that the response does contain a form in its - context, and that form has errors, if count were given, - it must match the exact numbers of errors - """ - context = getattr(response, "context", {}) - assert (context and context_name in context), \ - "The response did not contain a form." - errors = response.context[context_name]._errors - if count: - assert len(errors) == count, \ - "%d errors were found on the form, %d expected" % \ - (len(errors), count) - if message and message not in str(errors): - self.fail("Expected message not found, instead found: %s" - % ["%s: %s" % (key, [e for e in field_errors]) for - (key, field_errors) in errors.items()]) - else: - assert len(errors) > 0, "No errors were found on the form" - - def assertStatusCode(self, response, expected_code): - """Validates an expected status code. - - Matches camel case of other assert functions - """ - if response.status_code == expected_code: - return - self.fail('status code %r != %r: %s' % (response.status_code, - expected_code, - response.content)) - - def assertItemsCollectionEqual(self, response, items_list): - self.assertEqual(response.json, {"items": items_list}) - - def getAndAssertTableRowAction(self, response, table_name, - action_name, row_id): - table = response.context[table_name + '_table'] - rows = list(filter(lambda x: x.id == row_id, - table.data)) - self.assertEqual(1, len(rows), - "Did not find a row matching id '%s'" % row_id) - row_actions = table.get_row_actions(rows[0]) - actions = list(filter(lambda x: x.name == action_name, - row_actions)) - - msg_args = (action_name, table_name, row_id) - self.assertGreater( - len(actions), 0, - "No action named '%s' found in '%s' table for id '%s'" % msg_args) - - self.assertEqual( - 1, len(actions), - "Multiple actions named '%s' found in '%s' table for id '%s'" - % msg_args) - - return actions[0] - - def getAndAssertTableAction(self, response, table_name, action_name): - - table = response.context[table_name + '_table'] - table_actions = table.get_table_actions() - actions = list(filter(lambda x: x.name == action_name, - table_actions)) - msg_args = (action_name, table_name) - self.assertGreater( - len(actions), 0, - "No action named '%s' found in '%s' table" % msg_args) - - self.assertEqual( - 1, len(actions), - "More than one action named '%s' found in '%s' table" % msg_args) - - return actions[0] - - @staticmethod - def mock_rest_request(**args): - mock_args = { - 'user.is_authenticated': True, - 'is_ajax.return_value': True, - 'policy.check.return_value': True, - 'body': '' - } - mock_args.update(args) - return mock.Mock(**mock_args) - - def assert_mock_multiple_calls_with_same_arguments( - self, mocked_method, count, expected_call): - self.assertEqual(count, mocked_method.call_count) - mocked_method.assert_has_calls([expected_call] * count) - - -class BaseAdminViewTests(TestCase): - """Sets an active user with the "admin" role. - - For testing admin-only views and functionality. - """ - def setActiveUser(self, *args, **kwargs): - if "roles" not in kwargs: - kwargs['roles'] = [self.roles.admin._info] - super(BaseAdminViewTests, self).setActiveUser(*args, **kwargs) - - def setSessionValues(self, **kwargs): - settings.SESSION_ENGINE = 'django.contrib.sessions.backends.file' - engine = import_module(settings.SESSION_ENGINE) - store = engine.SessionStore() - for key in kwargs: - store[key] = kwargs[key] - self.request.session[key] = kwargs[key] - store.save() - self.session = store - self.client.cookies[settings.SESSION_COOKIE_NAME] = store.session_key - - -class APIMockTestCase(TestCase): - - def setUp(self): - super(APIMockTestCase, self).setUp() - utils.patch_middleware_get_user() - - -def mock_obj_to_dict(r): - return mock.Mock(**{'to_dict.return_value': r}) - - -def mock_factory(r): - """mocks all the attributes as well as the to_dict """ - mocked = mock_obj_to_dict(r) - mocked.configure_mock(**r) - return mocked diff --git a/qinling_dashboard/test/settings.py b/qinling_dashboard/test/settings.py deleted file mode 100644 index c89e69c..0000000 --- a/qinling_dashboard/test/settings.py +++ /dev/null @@ -1,39 +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. - -# Default to Horizons test settings to avoid any missing keys - -import openstack_dashboard.enabled # noqa: F811 -from openstack_dashboard.test.settings import * # noqa: F403,H303 -from openstack_dashboard.utils import settings - -import qinling_dashboard.enabled - -# pop these keys to avoid log warnings about deprecation -# update_dashboards will populate them anyway -HORIZON_CONFIG.pop('dashboards', None) # noqa: F405 -HORIZON_CONFIG.pop('default_dashboard', None) # noqa: F405 - -# Update the dashboards with heat_dashboard enabled files -# and current INSTALLED_APPS -settings.update_dashboards( - [ - openstack_dashboard.enabled, - qinling_dashboard.enabled, - ], - HORIZON_CONFIG, # noqa: F405 - INSTALLED_APPS # noqa: F405 -) - -# Remove duplicated apps -INSTALLED_APPS = list(set(INSTALLED_APPS)) # noqa: F405 diff --git a/qinling_dashboard/test/test_data/__init__.py b/qinling_dashboard/test/test_data/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qinling_dashboard/test/test_data/exceptions.py b/qinling_dashboard/test/test_data/exceptions.py deleted file mode 100644 index bf013e0..0000000 --- a/qinling_dashboard/test/test_data/exceptions.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2012 Nebula, 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. - -import qinlingclient.common.exceptions as qinling_exceptions - -from qinling_dashboard.test.test_data import utils - - -def create_stubbed_exception(cls, status_code=500): - msg = "Expected failure." - - def fake_init_exception(self, code=None, message=None, **kwargs): - if code is not None: - if hasattr(self, 'http_status'): - self.http_status = code - else: - self.code = code - self.message = message or self.__class__.message - - try: - # Neutron sometimes updates the message with additional - # information, like a reason. - self.message = self.message % kwargs - except Exception: - pass # We still have the main error message. - - def fake_str(self): - return str(self.message) - - cls.__init__ = fake_init_exception - cls.__str__ = fake_str - cls.silence_logging = True - return cls(status_code, msg) - - -def data(TEST): - TEST.exceptions = utils.TestDataContainer() - - qinling_exception = qinling_exceptions.HTTPException - TEST.exceptions.qinling = create_stubbed_exception(qinling_exception) diff --git a/qinling_dashboard/test/test_data/keystone_data.py b/qinling_dashboard/test/test_data/keystone_data.py deleted file mode 100644 index 4e2efac..0000000 --- a/qinling_dashboard/test/test_data/keystone_data.py +++ /dev/null @@ -1,339 +0,0 @@ -# Copyright 2012 Nebula, 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. - -import copy -from datetime import timedelta - -from django.conf import settings -from django.utils import datetime_safe - -from keystoneclient import access -from keystoneclient.v2_0 import tenants -from keystoneclient.v2_0 import users -from keystoneclient.v3.contrib.federation import identity_providers -from keystoneclient.v3.contrib.federation import mappings -from keystoneclient.v3.contrib.federation import protocols -from keystoneclient.v3 import domains - -from openstack_auth import user as auth_user - -from qinling_dashboard.test.test_data import utils - - -# Dummy service catalog with all service. -# All endpoint URLs should point to example.com. -# Try to keep them as accurate to real data as possible (ports, URIs, etc.) -SERVICE_CATALOG = [ - {"type": "compute", - "name": "nova", - "endpoints_links": [], - "endpoints": [ - {"region": "RegionOne", - "adminURL": "http://admin.nova.example.com:8774/v2", - "internalURL": "http://int.nova.example.com:8774/v2", - "publicURL": "http://public.nova.example.com:8774/v2"}, - {"region": "RegionTwo", - "adminURL": "http://admin.nova2.example.com:8774/v2", - "internalURL": "http://int.nova2.example.com:8774/v2", - "publicURL": "http://public.nova2.example.com:8774/v2"}]}, - {"type": "volumev2", - "name": "cinderv2", - "endpoints_links": [], - "endpoints": [ - {"region": "RegionOne", - "adminURL": "http://admin.nova.example.com:8776/v2", - "internalURL": "http://int.nova.example.com:8776/v2", - "publicURL": "http://public.nova.example.com:8776/v2"}, - {"region": "RegionTwo", - "adminURL": "http://admin.nova.example.com:8776/v2", - "internalURL": "http://int.nova.example.com:8776/v2", - "publicURL": "http://public.nova.example.com:8776/v2"}]}, - {"type": "image", - "name": "glance", - "endpoints_links": [], - "endpoints": [ - {"region": "RegionOne", - "adminURL": "http://admin.glance.example.com:9292", - "internalURL": "http://int.glance.example.com:9292", - "publicURL": "http://public.glance.example.com:9292"}]}, - {"type": "identity", - "name": "keystone", - "endpoints_links": [], - "endpoints": [ - {"region": "RegionOne", - "adminURL": "http://admin.keystone.example.com:35357/v2.0", - "internalURL": "http://int.keystone.example.com:5000/v2.0", - "publicURL": "http://public.keystone.example.com:5000/v2.0"}]}, - {"type": "object-store", - "name": "swift", - "endpoints_links": [], - "endpoints": [ - {"region": "RegionOne", - "adminURL": "http://admin.swift.example.com:8080/", - "internalURL": "http://int.swift.example.com:8080/", - "publicURL": "http://public.swift.example.com:8080/"}]}, - {"type": "network", - "name": "neutron", - "endpoints_links": [], - "endpoints": [ - {"region": "RegionOne", - "adminURL": "http://admin.neutron.example.com:9696/", - "internalURL": "http://int.neutron.example.com:9696/", - "publicURL": "http://public.neutron.example.com:9696/"}]}, - {"type": "ec2", - "name": "EC2 Service", - "endpoints_links": [], - "endpoints": [ - {"region": "RegionOne", - "adminURL": "http://admin.nova.example.com:8773/services/Admin", - "publicURL": "http://public.nova.example.com:8773/services/Cloud", - "internalURL": "http://int.nova.example.com:8773/services/Cloud"}]}, - {"type": "function-engine", - "name": "qinling", - "endpoints_links": [], - "endpoints": [ - {"region": "RegionOne", - "adminURL": "http://admin.heat.example.com:7070/v1", - "publicURL": "http://public.heat.example.com:7070/v1", - "internalURL": "http://int.heat.example.com:7070/v1"}]} -] - - -def data(TEST): - # Make a deep copy of the catalog to avoid persisting side-effects - # when tests modify the catalog. - TEST.service_catalog = copy.deepcopy(SERVICE_CATALOG) - TEST.tokens = utils.TestDataContainer() - TEST.domains = utils.TestDataContainer() - TEST.users = utils.TestDataContainer() - # TEST.groups = utils.TestDataContainer() - TEST.tenants = utils.TestDataContainer() - # TEST.role_assignments = utils.TestDataContainer() - # TEST.roles = utils.TestDataContainer() - # TEST.ec2 = utils.TestDataContainer() - - TEST.identity_providers = utils.TestDataContainer() - TEST.idp_mappings = utils.TestDataContainer() - TEST.idp_protocols = utils.TestDataContainer() - - # admin_role_dict = {'id': '1', - # 'name': 'admin'} - # admin_role = roles.Role(roles.RoleManager, admin_role_dict, loaded=True) - member_role_dict = {'id': "2", - 'name': settings.OPENSTACK_KEYSTONE_DEFAULT_ROLE} - # member_role = roles.Role(roles.RoleManager, - # member_role_dict, loaded=True) - # TEST.roles.add(admin_role, member_role) - # TEST.roles.admin = admin_role - # TEST.roles.member = member_role - - domain_dict = {'id': "1", - 'name': 'test_domain', - 'description': "a test domain.", - 'enabled': True} - domain_dict_2 = {'id': "2", - 'name': 'disabled_domain', - 'description': "a disabled test domain.", - 'enabled': False} - domain_dict_3 = {'id': "3", - 'name': 'another_test_domain', - 'description': "another test domain.", - 'enabled': True} - domain = domains.Domain(domains.DomainManager, domain_dict) - disabled_domain = domains.Domain(domains.DomainManager, domain_dict_2) - another_domain = domains.Domain(domains.DomainManager, domain_dict_3) - TEST.domains.add(domain, disabled_domain, another_domain) - TEST.domain = domain # Your "current" domain - - user_dict = {'id': "1", - 'name': 'test_user', - 'description': 'test_description', - 'email': 'test@example.com', - 'password': 'password', - 'token': 'test_token', - 'project_id': '1', - 'enabled': True, - 'domain_id': "1"} - user = users.User(None, user_dict) - user_dict = {'id': "2", - 'name': 'user_two', - 'description': 'test_description', - 'email': 'two@example.com', - 'password': 'password', - 'token': 'test_token', - 'project_id': '1', - 'enabled': True, - 'domain_id': "1"} - user2 = users.User(None, user_dict) - user_dict = {'id': "3", - 'name': 'user_three', - 'description': 'test_description', - 'email': 'three@example.com', - 'password': 'password', - 'token': 'test_token', - 'project_id': '1', - 'enabled': True, - 'domain_id': "1"} - user3 = users.User(None, user_dict) - user_dict = {'id': "4", - 'name': 'user_four', - 'description': 'test_description', - 'email': 'four@example.com', - 'password': 'password', - 'token': 'test_token', - 'project_id': '2', - 'enabled': True, - 'domain_id': "2"} - user4 = users.User(None, user_dict) - user_dict = {'id': "5", - 'name': 'user_five', - 'description': 'test_description', - 'email': None, - 'password': 'password', - 'token': 'test_token', - 'project_id': '2', - 'enabled': True, - 'domain_id': "1"} - user5 = users.User(None, user_dict) - TEST.users.add(user, user2, user3, user4, user5) - TEST.user = user # Your "current" user - TEST.user.service_catalog = copy.deepcopy(SERVICE_CATALOG) - - tenant_dict = {'id': "1", - 'name': 'test_tenant', - 'description': "a test tenant.", - 'enabled': True, - 'domain_id': '1', - 'domain_name': 'test_domain'} - tenant_dict_2 = {'id': "2", - 'name': 'disabled_tenant', - 'description': "a disabled test tenant.", - 'enabled': False, - 'domain_id': '2', - 'domain_name': 'disabled_domain'} - tenant_dict_3 = {'id': "3", - 'name': u'\u4e91\u89c4\u5219', - 'description': "an unicode-named tenant.", - 'enabled': True, - 'domain_id': '2', - 'domain_name': 'disabled_domain'} - tenant = tenants.Tenant(tenants.TenantManager, tenant_dict) - disabled_tenant = tenants.Tenant(tenants.TenantManager, tenant_dict_2) - tenant_unicode = tenants.Tenant(tenants.TenantManager, tenant_dict_3) - - TEST.tenants.add(tenant, disabled_tenant, tenant_unicode) - TEST.tenant = tenant # Your "current" tenant - - tomorrow = datetime_safe.datetime.now() + timedelta(days=1) - expiration = tomorrow.isoformat() - - scoped_token_dict = { - 'access': { - 'token': { - 'id': "test_token_id", - 'expires': expiration, - 'tenant': tenant_dict, - 'tenants': [tenant_dict]}, - 'user': { - 'id': "test_user_id", - 'name': "test_user", - 'roles': [member_role_dict]}, - 'serviceCatalog': TEST.service_catalog - } - } - - scoped_access_info = access.AccessInfo.factory(resp=None, - body=scoped_token_dict) - - unscoped_token_dict = { - 'access': { - 'token': { - 'id': "test_token_id", - 'expires': expiration}, - 'user': { - 'id': "test_user_id", - 'name': "test_user", - 'roles': [member_role_dict]}, - 'serviceCatalog': TEST.service_catalog - } - } - unscoped_access_info = access.AccessInfo.factory(resp=None, - body=unscoped_token_dict) - - scoped_token = auth_user.Token(scoped_access_info) - unscoped_token = auth_user.Token(unscoped_access_info) - TEST.tokens.add(scoped_token, unscoped_token) - TEST.token = scoped_token # your "current" token. - TEST.tokens.scoped_token = scoped_token - TEST.tokens.unscoped_token = unscoped_token - - idp_dict_1 = {'id': 'idp_1', - 'description': 'identity provider 1', - 'enabled': True, - 'remote_ids': ['rid_1', 'rid_2']} - idp_1 = identity_providers.IdentityProvider( - identity_providers.IdentityProviderManager, - idp_dict_1, loaded=True) - idp_dict_2 = {'id': 'idp_2', - 'description': 'identity provider 2', - 'enabled': True, - 'remote_ids': ['rid_3', 'rid_4']} - idp_2 = identity_providers.IdentityProvider( - identity_providers.IdentityProviderManager, - idp_dict_2, loaded=True) - TEST.identity_providers.add(idp_1, idp_2) - - idp_mapping_dict = { - "id": "mapping_1", - "rules": [ - { - "local": [ - { - "user": { - "name": "{0}" - } - }, - { - "group": { - "id": "0cd5e9" - } - } - ], - "remote": [ - { - "type": "UserName" - }, - { - "type": "orgPersonType", - "not_any_of": [ - "Contractor", - "Guest" - ] - } - ] - } - ] - } - idp_mapping = mappings.Mapping( - mappings.MappingManager(None), - idp_mapping_dict) - TEST.idp_mappings.add(idp_mapping) - - idp_protocol_dict_1 = {'id': 'protocol_1', - 'mapping_id': 'mapping_1'} - idp_protocol = protocols.Protocol( - protocols.ProtocolManager, - idp_protocol_dict_1, - loaded=True) - TEST.idp_protocols.add(idp_protocol) diff --git a/qinling_dashboard/test/test_data/qinling_data.py b/qinling_dashboard/test/test_data/qinling_data.py deleted file mode 100644 index f254e46..0000000 --- a/qinling_dashboard/test/test_data/qinling_data.py +++ /dev/null @@ -1,104 +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. - -from qinlingclient.v1 import function -from qinlingclient.v1 import function_execution -from qinlingclient.v1 import function_version -from qinlingclient.v1 import runtime - -from qinling_dashboard.test.test_data import utils - - -PROJECT_ID = "87173d0c07d547bfa1343cabe2e6fe69" -RUNTIME_ID_BASE = "6cb1f505-9a42-4569-a94d-9c2f4b7e7b4{0}" -FUNCTION_ID_BASE = "aacb5032-f8b9-4ad5-8fd4-8017d0d1c54{0}" -EXECUTION_ID_BASE = "f0b5d7f5-d1f1-4f3e-9080-16e4cd918f9{0}" -VERSION_ID_BASE = "30c3e142-2850-4a89-90a7-0a4e4d654f{0}{1}" - - -def data(TEST): - TEST.runtimes = utils.TestDataContainer() - TEST.functions = utils.TestDataContainer() - TEST.executions = utils.TestDataContainer() - TEST.versions = utils.TestDataContainer() - - for i in range(10): - runtime_data = { - "id": RUNTIME_ID_BASE.format(i), - "name": "python2.7-runtime-{0}".format(i), - "status": "available", - "created_at": "2018-07-11 01:09:13", - "description": None, - "image": "openstackqinling/python-runtime", - "updated_at": "2018-07-11 01:09:28", - "is_public": True, - "project_id": PROJECT_ID, - } - rt = runtime.Runtime(runtime.RuntimeManager(None), runtime_data) - TEST.runtimes.add(rt) - - for i in range(10): - function_data = { - "id": FUNCTION_ID_BASE.format(i), - "count": 0, - "code": "{\"source\": \"package\", " - "\"md5sum\": \"976325c9b41bc5a2ddb54f3493751f7e\"}", - "description": None, - "created_at": "2018-08-01 08:33:50", - "updated_at": None, - "latest_version": 0, - "memory_size": 33554432, - "timeout": None, - "entry": "qinling_test.main", - "project_id": PROJECT_ID, - "cpu": 100, - "runtime_id": RUNTIME_ID_BASE.format(i), - "name": "github_test" - } - func = function.Function(function.FunctionManager(None), function_data) - TEST.functions.add(func) - - for i in range(10): - execution_data = { - "status": "success", - "project_id": PROJECT_ID, - "description": None, - "updated_at": "2018-08-01 06:09:58", - "created_at": "2018-08-01 06:09:55", - "sync": True, - "function_version": 0, - "result": "{\"duration\": 0.788, \"output\": 30}", - "input": None, - "function_id": FUNCTION_ID_BASE.format(i), - "id": EXECUTION_ID_BASE.format(i), - } - execution = function_execution.FunctionExecution( - function_execution.ExecutionManager(None), execution_data) - TEST.executions.add(execution) - - # Each mocked function has 10 of version data. - for i in range(10): - this_function_id = FUNCTION_ID_BASE.format(i) - for j in range(10): - version_data = { - "count": 0, - "version_number": j, - "function_id": this_function_id, - "description": "", - "created_at": "2018-08-03 02:01:44", - "updated_at": None, - "project_id": PROJECT_ID, - "id": VERSION_ID_BASE.format(i, j) - } - version = function_version.FunctionVersion( - function_version.FunctionVersionManager(None), version_data) - TEST.versions.add(version) diff --git a/qinling_dashboard/test/test_data/utils.py b/qinling_dashboard/test/test_data/utils.py deleted file mode 100644 index 4054984..0000000 --- a/qinling_dashboard/test/test_data/utils.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2012 Nebula, 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. - - -def load_test_data(load_onto=None): - from qinling_dashboard.test.test_data import exceptions - from qinling_dashboard.test.test_data import keystone_data - from qinling_dashboard.test.test_data import qinling_data - - # The order of these loaders matters, some depend on others. - loaders = ( - exceptions.data, - keystone_data.data, - qinling_data.data, - ) - if load_onto: - for data_func in loaders: - data_func(load_onto) - return load_onto - else: - return TestData(*loaders) - - -class TestData(object): - """Holder object for test data. - - Any functions passed to the init method will be called with the - ``TestData`` object as their only argument. - They can then load data onto the object as desired. - - The idea is to use the instantiated object like this:: - - >>> import qinling_data - >>> TEST = TestData(qinling_data.data) - >>> TEST.runtimes.list() - [, ] - >>> TEST.runtimes.first() - - - You can load as little or as much data as you like as long as the loaders - don't conflict with each other. - - See the - :class:`~openstack_dashboard.test.test_data.utils.TestDataContainer` - class for a list of available methods. - """ - def __init__(self, *args): - for data_func in args: - data_func(self) - - -class TestDataContainer(object): - """A container for test data objects. - - The behavior of this class is meant to mimic a "manager" class, which - has convenient shortcuts for common actions like "list", "filter", "get", - and "add". - """ - def __init__(self): - self._objects = [] - - def add(self, *args): - """Add a new object to this container. - - Generally this method should only be used during data loading, since - adding data during a test can affect the results of other tests. - """ - for obj in args: - if obj not in self._objects: - self._objects.append(obj) - - def list(self): - """Returns a list of all objects in this container.""" - return self._objects - - def filter(self, filtered=None, **kwargs): - """Returns objects whose attributes match the given kwargs.""" - if filtered is None: - filtered = self._objects - try: - key, value = kwargs.popitem() - except KeyError: - # We're out of filters, return - return filtered - - def get_match(obj): - return hasattr(obj, key) and getattr(obj, key) == value - - filtered = [obj for obj in filtered if get_match(obj)] - return self.filter(filtered=filtered, **kwargs) - - def get(self, **kwargs): - """Returns a single object whose attributes match the given kwargs. - - An error will be raised if the arguments - provided don't return exactly one match. - """ - matches = self.filter(**kwargs) - if not matches: - raise Exception("No matches found.") - elif len(matches) > 1: - raise Exception("Multiple matches found.") - else: - return matches.pop() - - def first(self): - """Returns the first object from this container.""" - return self._objects[0] - - def count(self): - return len(self._objects) diff --git a/qinling_dashboard/test/tests/__init__.py b/qinling_dashboard/test/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qinling_dashboard/test/tests/api/__init__.py b/qinling_dashboard/test/tests/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qinling_dashboard/test/tests/api/test_qinling.py b/qinling_dashboard/test/tests/api/test_qinling.py deleted file mode 100644 index b26c5ee..0000000 --- a/qinling_dashboard/test/tests/api/test_qinling.py +++ /dev/null @@ -1,272 +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. - -from unittest import mock - -from qinling_dashboard import api -from qinling_dashboard.test import helpers as test - - -class QinlingApiTests(test.APIMockTestCase): - - # Runtimes - @mock.patch.object(api.qinling, 'qinlingclient') - def test_runtimes_list(self, mock_qinlingclient): - """Test for api.qinling.runtimes_list()""" - runtimes = self.runtimes.list() - - qclient = mock_qinlingclient.return_value - qclient.runtimes.list.return_value = runtimes - - result = api.qinling.runtimes_list(self.request) - self.assertCountEqual(result, runtimes) - - qclient.runtimes.list.assert_called_once_with() - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_runtime_get(self, mock_qinlingclient): - """Test for api.qinling.runtime_get()""" - runtime = self.runtimes.first() - - qclient = mock_qinlingclient.return_value - qclient.runtimes.get.return_value = runtime - - result = api.qinling.runtime_get(self.request, runtime.id) - self.assertEqual(result, runtime) - - qclient.runtimes.get.assert_called_once_with(runtime.id) - - # Functions - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_create(self, mock_qinlingclient): - """Test for api.qinling.function_create()""" - func = self.functions.first() - - qclient = mock_qinlingclient.return_value - qclient.functions.create.return_value = func - - params = {} - result = api.qinling.function_create(self.request, **params) - self.assertEqual(result, func) - - qclient.functions.create.assert_called_once_with(**params) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_update(self, mock_qinlingclient): - """Test for api.qinling.function_update()""" - func = self.functions.first() - - qclient = mock_qinlingclient.return_value - qclient.functions.update.return_value = func - - params = {} - result = api.qinling.function_update(self.request, func.id, **params) - self.assertEqual(result, func) - - qclient.functions.update.assert_called_once_with(func.id, **params) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_delete(self, mock_qinlingclient): - """Test for api.qinling.function_delete()""" - func = self.functions.first() - - qclient = mock_qinlingclient.return_value - qclient.functions.delete.return_value = None - - result = api.qinling.function_delete(self.request, func.id) - self.assertIsNone(result) - - qclient.functions.delete.assert_called_once_with(func.id) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_functions_list(self, mock_qinlingclient): - """Test for api.qinling.functions_list()""" - functions = self.functions.list() - - qclient = mock_qinlingclient.return_value - qclient.functions.list.return_value = functions - - result = api.qinling.functions_list(self.request) - self.assertCountEqual(result, functions) - - qclient.functions.list.assert_called_once_with() - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_get(self, mock_qinlingclient): - """Test for api.qinling.function_get()""" - func = self.functions.first() - - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = func - - result = api.qinling.function_get(self.request, func.id) - self.assertEqual(result, func) - - qclient.functions.get.assert_called_once_with(func.id) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_download(self, mock_qinlingclient): - """Test for api.qinling.function_download()""" - func = self.functions.first() - - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = func - - result = api.qinling.function_download(self.request, func.id) - self.assertEqual(result, func) - - qclient.functions.get.assert_called_once_with(func.id, download=True) - - # Function Executions - @mock.patch.object(api.qinling, 'qinlingclient') - def test_execution_create(self, mock_qinlingclient): - """Test for api.qinling.execution_create()""" - func = self.functions.first() - execution = self.executions.first() - - qclient = mock_qinlingclient.return_value - qclient.function_executions.create.return_value = execution - - result = api.qinling.execution_create(self.request, func.id, - version=1, sync=True, - input=None) - self.assertEqual(result, execution) - - qclient.function_executions.create.assert_called_once_with(func.id, - 1, - True, - None) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_execution_delete(self, mock_qinlingclient): - """Test for api.qinling.execution_delete()""" - execution = self.executions.first() - - qclient = mock_qinlingclient.return_value - qclient.function_executions.create.return_value = execution - - result = api.qinling.execution_delete(self.request, execution.id) - self.assertIsNone(result) - - qclient.function_executions.delete.\ - assert_called_once_with(execution.id) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_execution_log_get(self, mock_qinlingclient): - """Test for api.qinling.execution_log_get()""" - execution = self.executions.first() - log_contents = "this is log line." - - class FakeResponse(object): - _content = log_contents - - qclient = mock_qinlingclient.return_value - qclient.function_executions.http_client.json_request.\ - return_value = FakeResponse(), "dummybody" - - result = api.qinling.execution_log_get(self.request, execution.id) - self.assertEqual(result, log_contents) - - url = '/v1/executions/%s/log' % execution.id - qclient.function_executions.http_client.\ - json_request.assert_called_once_with(url, 'GET') - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_executions_list(self, mock_qinlingclient): - """Test for api.qinling.executions_list()""" - executions = self.executions.list() - - qclient = mock_qinlingclient.return_value - qclient.function_executions.list.return_value = executions - - result = api.qinling.executions_list(self.request) - self.assertCountEqual(result, executions) - - qclient.function_executions.list.assert_called_once_with() - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_execution_get(self, mock_qinlingclient): - """Test for api.qinling.execution_get()""" - execution = self.executions.first() - - qclient = mock_qinlingclient.return_value - qclient.function_executions.get.return_value = execution - - result = api.qinling.execution_get(self.request, execution.id) - self.assertEqual(result, execution) - - qclient.function_executions.get.assert_called_once_with(execution.id) - - # Function Versions - @mock.patch.object(api.qinling, 'qinlingclient') - def test_versions_list(self, mock_qinlingclient): - """Test for api.qinling.versions_list()""" - versions = self.versions.list() - func = self.functions.first() - - this_function_id = func.id - - my_versions = [v for v in versions - if v.function_id == this_function_id] - - qclient = mock_qinlingclient.return_value - qclient.function_versions.list.return_value = my_versions - - result = api.qinling.versions_list(self.request, - this_function_id) - self.assertCountEqual(result, my_versions) - - qclient.function_versions.list.\ - assert_called_once_with(this_function_id) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_version_get(self, mock_qinlingclient): - """Test for api.qinling.version_get()""" - versions = self.versions.list() - func = self.functions.first() - - this_function_id = func.id - this_version_number = 1 - - my_version = [v for v in versions - if v.function_id == this_function_id and - v.version_number == this_version_number][0] - - qclient = mock_qinlingclient.return_value - qclient.function_versions.get.return_value = my_version - - result = api.qinling.version_get(self.request, - this_function_id, - this_version_number) - self.assertEqual(result, my_version) - - qclient.function_versions.get.\ - assert_called_once_with(this_function_id, this_version_number) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_version_create(self, mock_qinlingclient): - """Test for api.qinling.version_create()""" - version = self.versions.first() - func = self.functions.first() - - this_function_id = func.id - - qclient = mock_qinlingclient.return_value - qclient.function_versions.create.return_value = version - - result = api.qinling.version_create(self.request, - this_function_id, - "description sample") - self.assertEqual(result, version) - - qclient.function_versions.create.\ - assert_called_once_with(this_function_id, "description sample") diff --git a/qinling_dashboard/test/tests/content/__init__.py b/qinling_dashboard/test/tests/content/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qinling_dashboard/test/tests/content/test_executions.py b/qinling_dashboard/test/tests/content/test_executions.py deleted file mode 100644 index 3942f60..0000000 --- a/qinling_dashboard/test/tests/content/test_executions.py +++ /dev/null @@ -1,329 +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 json -from unittest import mock - - -from django.urls import reverse - -from django.utils.http import urlunquote - -from qinling_dashboard import api - -from qinling_dashboard.test import helpers as test - - -INDEX_TEMPLATE = 'horizon/common/_data_table_view.html' -INDEX_URL = reverse('horizon:project:executions:index') - - -class ExecutionsTests(test.TestCase): - - @test.create_mocks({ - api.qinling: [ - 'executions_list', - 'execution_delete', - ]}) - def test_execution_delete(self): - data_executions = self.executions.list() - data_execution = self.executions.first() - execution_id = data_execution.id - - self.mock_executions_list.return_value = data_executions - self.mock_execution_delete.return_value = None - - form_data = {'action': 'executions__delete__%s' % execution_id} - res = self.client.post(INDEX_URL, form_data) - self.assertRedirectsNoFollow(res, INDEX_URL) - - self.mock_execution_delete.assert_called_once_with( - test.IsHttpRequest(), execution_id) - - @test.create_mocks({ - api.qinling: [ - 'execution_create', - 'functions_list', - 'function_get', - 'versions_list', - ]}) - def test_execution_create(self): - data_execution = self.executions.first() - - data_functions = self.functions.list() - - data_function = self.functions.first() - function_id = data_function.id - - data_versions = self.versions.list() - my_versions = [v for v in data_versions - if v.function_id == function_id] - - self.mock_versions_list.return_value = data_versions - self.mock_function_get.return_value = data_function - self.mock_functions_list.return_value = data_functions - self.mock_execution_create.return_value = data_execution - self.mock_versions_list.return_value = my_versions - - form_data = {'func': function_id, - 'version': 0, - 'sync': True, - 'input_params': 'K1=V1\nK2=V2'} - - url = reverse('horizon:project:executions:create') - res = self.client.post(url, form_data) - - self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, INDEX_URL) - - input_dict = {'K1': 'V1', 'K2': 'V2'} - input_params = json.dumps(input_dict) - - self.mock_execution_create.assert_called_once_with( - test.IsHttpRequest(), function_id, 0, True, input_params) - - @test.create_mocks({ - api.qinling: [ - 'execution_create', - 'functions_list', - 'function_get', - 'versions_list', - ]}) - def test_execution_create_function_input_params_is_not_key_value(self): - - data_functions = self.functions.list() - - data_function = self.functions.first() - function_id = data_function.id - - data_versions = self.versions.list() - my_versions = [v for v in data_versions - if v.function_id == function_id] - - self.mock_versions_list.return_value = data_versions - self.mock_function_get.return_value = data_function - self.mock_functions_list.return_value = data_functions - self.mock_versions_list.return_value = my_versions - - form_data = {'func': function_id, - 'version': 0, - 'sync': True, - 'input_params': 'K1=V1\nK2='} - - url = reverse('horizon:project:executions:create') - res = self.client.post(url, form_data) - - expected_msg = "Not key-value pair." - self.assertContains(res, expected_msg) - - @test.create_mocks({ - api.qinling: [ - 'execution_create', - 'functions_list', - 'function_get', - 'versions_list', - ]}) - def test_execution_create_function_version_does_not_exist(self): - - data_functions = self.functions.list() - - data_function = self.functions.first() - function_id = data_function.id - - data_versions = self.versions.list() - my_versions = [v for v in data_versions - if v.function_id == function_id] - - self.mock_versions_list.return_value = data_versions - self.mock_function_get.return_value = data_function - self.mock_functions_list.return_value = data_functions - self.mock_versions_list.return_value = my_versions - - invalid_version = 10 - form_data = {'func': function_id, - 'version': invalid_version, - 'sync': True, - 'input_params': ""} - - url = reverse('horizon:project:executions:create') - res = self.client.post(url, form_data) - - expected_msg = "This function does not " \ - "have specified version number: %s" % invalid_version - self.assertContains(res, expected_msg) - - @test.create_mocks({ - api.qinling: [ - 'execution_create', - 'functions_list', - 'function_get', - 'versions_list', - ]}) - def test_execution_create_function_id_is_not_in_choices(self): - - data_functions = self.functions.list() - - data_function = self.functions.first() - function_id = data_function.id - - data_versions = self.versions.list() - my_versions = [v for v in data_versions - if v.function_id == function_id] - - self.mock_versions_list.return_value = data_versions - self.mock_function_get.return_value = data_function - self.mock_functions_list.return_value = data_functions - self.mock_versions_list.return_value = my_versions - - form_data = {'func': function_id + 'a', # function does not exist - 'version': 0, - 'sync': True, - 'input_params': ""} - - url = reverse('horizon:project:executions:create') - res = self.client.post(url, form_data) - - expected_msg = \ - "%s is not one of the available choices." % (function_id + 'a') - self.assertContains(res, expected_msg) - - # You should not mock api.qinling.executions_list/get itself here, - # because inside of executions_list, execution.result is converted - # from str to dict. - # If you mock everything about this executions_list, above conversion - # method won't be called then it causes error in table rendering. - @mock.patch.object(api.qinling, 'qinlingclient') - def test_index(self, mock_qinlingclient): - data_executions = self.executions.list() - - qclient = mock_qinlingclient.return_value - qclient.function_executions.list.return_value = data_executions - - res = self.client.get(INDEX_URL) - - self.assertTemplateUsed(res, INDEX_TEMPLATE) - executions = res.context['executions_table'].data - self.assertCountEqual(executions, self.executions.list()) - - qclient.function_executions.list.assert_called_once_with() - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_index_executions_list_returns_exception(self, mock_qinlingclient): - # data_executions = self.executions.list() - - qclient = mock_qinlingclient.return_value - qclient.function_executions.list.side_effect = self.exceptions.qinling - - res = self.client.get(INDEX_URL) - - self.assertTemplateUsed(res, INDEX_TEMPLATE) - - self.assertEqual(len(res.context['executions_table'].data), 0) - self.assertMessageCount(res, error=1) - - qclient.function_executions.list.assert_called_once_with() - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_detail(self, mock_qinlingclient): - execution_id = self.executions.first().id - data_execution = self.executions.first() - - qclient = mock_qinlingclient.return_value - qclient.function_executions.get.return_value = data_execution - - url = urlunquote(reverse('horizon:project:executions:detail', - args=[execution_id])) - res = self.client.get(url) - - result_execution = res.context['execution'] - - self.assertEqual(execution_id, result_execution.id) - - self.assertTemplateUsed(res, 'project/executions/detail.html') - - qclient.function_executions.get.assert_called_once_with(execution_id) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_detail_execution_get_returns_exception(self, mock_qinlingclient): - execution_id = self.executions.first().id - - qclient = mock_qinlingclient.return_value - qclient.function_executions.get.side_effect = self.exceptions.qinling - - url = urlunquote(reverse('horizon:project:executions:detail', - args=[execution_id])) - res = self.client.get(url) - - redir_url = INDEX_URL - self.assertRedirectsNoFollow(res, redir_url) - - qclient.function_executions.get.assert_called_once_with(execution_id) - - @test.create_mocks({ - api.qinling: [ - 'execution_get', - 'execution_log_get', - ]}) - def test_detail_execution_log_tab(self): - execution_id = self.executions.first().id - log_contents = "this is log line." - - self.mock_execution_get.return_value = self.executions.first() - self.mock_execution_log_get.return_value = log_contents - - url_base = 'horizon:project:executions:detail_execution_logs' - url = urlunquote(reverse(url_base, args=[execution_id])) - res = self.client.get(url) - - result_logs = res.context['execution_logs'] - - self.assertTemplateUsed(res, 'project/executions/detail.html') - self.assertEqual(log_contents, result_logs) - - self.mock_execution_get.assert_has_calls( - [ - mock.call(test.IsHttpRequest(), execution_id), - ]) - self.mock_execution_log_get.assert_has_calls( - [ - mock.call(test.IsHttpRequest(), execution_id), - ]) - - @test.create_mocks({ - api.qinling: [ - 'execution_get', - 'execution_log_get', - ]}) - def test_detail_execution_log_tab_log_get_returns_exception(self): - execution_id = self.executions.first().id - - self.mock_execution_get.return_value = self.executions.first() - self.mock_execution_log_get.side_effect = self.exceptions.qinling - - url_base = 'horizon:project:executions:detail_execution_logs' - url = urlunquote(reverse(url_base, args=[execution_id])) - res = self.client.get(url) - - result_logs = res.context['execution_logs'] - - self.assertTemplateUsed(res, 'project/executions/detail.html') - - self.assertEqual(result_logs, "") - - self.mock_execution_get.assert_has_calls( - [ - mock.call(test.IsHttpRequest(), execution_id), - ]) - self.mock_execution_log_get.assert_has_calls( - [ - mock.call(test.IsHttpRequest(), execution_id), - ]) diff --git a/qinling_dashboard/test/tests/content/test_functions.py b/qinling_dashboard/test/tests/content/test_functions.py deleted file mode 100644 index d6fe6de..0000000 --- a/qinling_dashboard/test/tests/content/test_functions.py +++ /dev/null @@ -1,959 +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 unittest import mock - -from django.core.files import uploadedfile - -from django.http import response - -from django.urls import reverse - -from django.utils.http import urlunquote - -from qinling_dashboard import api -from qinling_dashboard.content.functions import forms as project_fm -from qinling_dashboard.test import helpers as test -from qinling_dashboard.utils import calculate_md5 - - -INDEX_TEMPLATE = 'horizon/common/_data_table_view.html' -INDEX_URL = reverse('horizon:project:functions:index') -FULL_FORM = { - "name": "", - "description": "", - "cpu": "", - "memory_size": "", - "code_type": "", - "package_file": "", - "runtime": "", - "entry": "", - "swift_container": "", - "swift_object": "", - "image": "", -} - -FILE_CONTENT = b'DUMMY_FILE' - - -class FunctionsTests(test.TestCase): - - def _mock_function_version_list(self, mock_qinlingclient): - - data_functions = self.functions.list() - - def _versions_list_side_effect(function_id): - all_versions = self.versions.list() - my_versions = [v for v in all_versions - if v.function_id == function_id] - return my_versions - - qclient = mock_qinlingclient.return_value - - # mock function_versions.list - qclient.function_versions.list.side_effect = \ - _versions_list_side_effect - - # mock functions.list - qclient.functions.list.return_value = data_functions - - def _create_temp_file(self): - temp_file = uploadedfile.SimpleUploadedFile( - name='aaaa.zip', - content=FILE_CONTENT, - content_type='application/zip', - - ) - return temp_file - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_update_image_case(self, mock_qinlingclient): - """Test update function by image""" - self._mock_function_version_list(mock_qinlingclient) - - func = self.functions.first() - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = func - qclient.functions.update.return_value = self.functions.first() - qclient.runtimes.list.return_value = self.runtimes.list() - - image = "dummy/image" - - form_data = {} - form_data.update({ - "function_id": func.id, - "name": "test_name", - "description": "description", - "cpu": project_fm.CPU_MIN_VALUE, - "memory_size": project_fm.MEMORY_MIN_VALUE, - "code_type": "image", - "image": image, - }) - - url = reverse('horizon:project:functions:update', args=[func.id]) - res = self.client.post(url, form_data) - - self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, INDEX_URL) - - # create expected form data. - actual_form_data = copy.deepcopy(form_data) - - del actual_form_data['code_type'] - del actual_form_data['function_id'] - del actual_form_data['image'] - - qclient.functions.update.\ - assert_called_once_with(func.id, **actual_form_data) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_update_swift_case(self, mock_qinlingclient): - """Test update function by swift""" - self._mock_function_version_list(mock_qinlingclient) - - func = self.functions.first() - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = func - qclient.functions.update.return_value = self.functions.first() - qclient.runtimes.list.return_value = self.runtimes.list() - - swift_container = "dummy_container" - swift_object = "dummy_object" - - form_data = {} - form_data.update({ - "function_id": func.id, - "name": "test_name", - "description": "description", - "cpu": project_fm.CPU_MIN_VALUE, - "memory_size": project_fm.MEMORY_MIN_VALUE, - "code_type": "swift", - "entry_swift": "main.main", - "swift_container": swift_container, - "swift_object": swift_object, - }) - - url = reverse('horizon:project:functions:update', args=[func.id]) - res = self.client.post(url, form_data) - - self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, INDEX_URL) - - # create expected form data. - actual_form_data = copy.deepcopy(form_data) - - del actual_form_data['code_type'] - del actual_form_data['function_id'] - del actual_form_data['entry_swift'] - - del actual_form_data['swift_container'] - del actual_form_data['swift_object'] - - qclient.functions.update.\ - assert_called_once_with(func.id, **actual_form_data) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_update_package_case_if_blank_value_is_correctly_handled( - self, mock_qinlingclient): - """Test update function by package - - check if blank string is correctly handled as meaning of - 'removing values' - """ - self._mock_function_version_list(mock_qinlingclient) - - func = self.functions.first() - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = func - qclient.functions.update.return_value = self.functions.first() - qclient.runtimes.list.return_value = self.runtimes.list() - - form_data = {} - form_data.update({ - "function_id": func.id, - "name": "", - "description": "", - "cpu": "", - "memory_size": "", - "code_type": "package", - "entry": "", - }) - - url = reverse('horizon:project:functions:update', args=[func.id]) - res = self.client.post(url, form_data) - - self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, INDEX_URL) - - # create expected form data. - actual_form_data = copy.deepcopy(form_data) - - del actual_form_data['code_type'] - del actual_form_data['cpu'] - del actual_form_data['memory_size'] - del actual_form_data['function_id'] - - qclient.functions.update.\ - assert_called_once_with(func.id, **actual_form_data) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_update_package_case(self, mock_qinlingclient): - """Test update function by package""" - self._mock_function_version_list(mock_qinlingclient) - - func = self.functions.first() - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = func - qclient.functions.update.return_value = self.functions.first() - qclient.runtimes.list.return_value = self.runtimes.list() - - temp_file = self._create_temp_file() - - form_data = {} - form_data.update({ - "function_id": func.id, - "name": "test_name", - "description": "description", - "cpu": project_fm.CPU_MIN_VALUE, - "memory_size": project_fm.MEMORY_MIN_VALUE, - "code_type": "package", - "entry": "main.main", - "package_file": temp_file, - }) - - url = reverse('horizon:project:functions:update', args=[func.id]) - res = self.client.post(url, form_data) - - self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, INDEX_URL) - - # create expected form data. - actual_form_data = copy.deepcopy(form_data) - - del actual_form_data['code_type'] - del actual_form_data['package_file'] - del actual_form_data['function_id'] - actual_form_data.update({ - 'package': FILE_CONTENT, - 'code': {'source': 'package', - 'md5sum': calculate_md5(temp_file)} - }) - - qclient.functions.update.\ - assert_called_once_with(func.id, **actual_form_data) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_create_swift_case_no_runtime_specified( - self, mock_qinlingclient): - """Test error case of function creation - - Because no runtime is specified. - """ - delete_key = ['runtime_swift'] - message = 'You must specify runtime.' - self._function_create_swift_case_error(mock_qinlingclient, - delete_key, - message) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_create_swift_case_no_container_specified( - self, mock_qinlingclient): - """Test error case of function creation - - Because no swift container is specified. - """ - delete_key = ['swift_container'] - message = 'You must specify container and object ' \ - 'both in case code type is Swift.' - self._function_create_swift_case_error(mock_qinlingclient, - delete_key, - message) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_create_swift_case_no_object_specified( - self, mock_qinlingclient): - """Test error case of function creation - - Because no swift object is specified. - """ - delete_key = ['swift_object'] - message = 'You must specify container and object ' \ - 'both in case code type is Swift.' - self._function_create_swift_case_error(mock_qinlingclient, - delete_key, - message) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_create_swift_case_no_container_object_specified( - self, mock_qinlingclient): - """Test error case of function creation - - Because both swift container/object are not specified. - """ - delete_key = ['swift_container', 'swift_object'] - message = 'You must specify container and object ' \ - 'both in case code type is Swift.' - self._function_create_swift_case_error(mock_qinlingclient, - delete_key, - message) - - def _function_create_swift_case_error(self, mock_qinlingclient, - delete_key=None, message=''): - """Base function for function creation error test in swift case""" - if not delete_key: - delete_key = [] - - self._mock_function_version_list(mock_qinlingclient) - - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = self.functions.first() - qclient.functions.create.return_value = self.functions.first() - qclient.runtimes.list.return_value = self.runtimes.list() - - form_data = copy.deepcopy(FULL_FORM) - - swift_container = "dummy_container" - swift_object = "dummy_object" - runtime_id = self.runtimes.first().id - - form_data.update({ - "name": "test_name", - "description": "description", - "cpu": project_fm.CPU_MIN_VALUE, - "memory_size": project_fm.MEMORY_MIN_VALUE, - "code_type": "swift", - "swift_container": swift_container, - "swift_object": swift_object, - "runtime_swift": runtime_id, - }) - - for k in delete_key: - if k in form_data: - del form_data[k] - - url = reverse('horizon:project:functions:create') - res = self.client.post(url, form_data) - - self.assertContains(res, message) - qclient.functions.create.assert_not_called() - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_create_swift_case(self, mock_qinlingclient): - """Test create function by swift container/object""" - self._mock_function_version_list(mock_qinlingclient) - - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = self.functions.first() - qclient.functions.create.return_value = self.functions.first() - qclient.runtimes.list.return_value = self.runtimes.list() - - form_data = copy.deepcopy(FULL_FORM) - - swift_container = "dummy_container" - swift_object = "dummy_object" - runtime_id = self.runtimes.first().id - - form_data.update({ - "name": "test_name", - "description": "description", - "cpu": project_fm.CPU_MIN_VALUE, - "memory_size": project_fm.MEMORY_MIN_VALUE, - "code_type": "swift", - "swift_container": swift_container, - "swift_object": swift_object, - "runtime_swift": runtime_id, - }) - - url = reverse('horizon:project:functions:create') - res = self.client.post(url, form_data) - - self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, INDEX_URL) - - # create expected form data. - actual_form_data = copy.deepcopy(form_data) - - for k, v in form_data.items(): - if not v: - del actual_form_data[k] - del actual_form_data['code_type'] - del actual_form_data['swift_container'] - del actual_form_data['swift_object'] - - # PIOST value "runtine_swift" to Horizon - # will be set as "runtime" in POST value to Qinling. - tmp_swift_runtime = form_data['runtime_swift'] - del actual_form_data['runtime_swift'] - actual_form_data.update({'runtime': tmp_swift_runtime}) - - actual_form_data.update({ - 'code': { - 'source': 'swift', - 'swift': { - 'container': swift_container, - 'object': swift_object, - } - } - }) - - qclient.functions.create.\ - assert_called_once_with(**actual_form_data) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_create_image_case_error(self, mock_qinlingclient): - """Test error case of function creation from image. - - Error case because no image is specified. - """ - self._mock_function_version_list(mock_qinlingclient) - - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = self.functions.first() - qclient.functions.create.return_value = self.functions.first() - qclient.runtimes.list.return_value = self.runtimes.list() - - form_data = copy.deepcopy(FULL_FORM) - - form_data.update({ - "name": "test_name", - "description": "description", - "cpu": project_fm.CPU_MIN_VALUE, - "memory_size": project_fm.MEMORY_MIN_VALUE, - "code_type": "image", - }) - - url = reverse('horizon:project:functions:create') - res = self.client.post(url, form_data) - - self.assertContains(res, 'You must specify Docker image.') - qclient.functions.create.assert_not_called() - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_create_image_case(self, mock_qinlingclient): - """Test create function by image""" - self._mock_function_version_list(mock_qinlingclient) - - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = self.functions.first() - qclient.functions.create.return_value = self.functions.first() - qclient.runtimes.list.return_value = self.runtimes.list() - - form_data = copy.deepcopy(FULL_FORM) - - image = "dummy/image" - - form_data.update({ - "name": "test_name", - "description": "description", - "cpu": project_fm.CPU_MIN_VALUE, - "memory_size": project_fm.MEMORY_MIN_VALUE, - "code_type": "image", - "image": image - }) - - url = reverse('horizon:project:functions:create') - res = self.client.post(url, form_data) - - self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, INDEX_URL) - - # create expected form data. - actual_form_data = copy.deepcopy(form_data) - for k, v in form_data.items(): - if not v: - del actual_form_data[k] - del actual_form_data['code_type'] - del actual_form_data['image'] - actual_form_data.update({ - 'code': { - 'source': 'image', - 'image': image - } - }) - - qclient.functions.create.\ - assert_called_once_with(**actual_form_data) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_create_package_case(self, mock_qinlingclient): - """Test create function by package""" - self._mock_function_version_list(mock_qinlingclient) - - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = self.functions.first() - qclient.functions.create.return_value = self.functions.first() - qclient.runtimes.list.return_value = self.runtimes.list() - - runtime = self.runtimes.first() - - temp_file = self._create_temp_file() - - form_data = copy.deepcopy(FULL_FORM) - form_data.update({ - "name": "test_name", - "description": "description", - "cpu": project_fm.CPU_MIN_VALUE, - "memory_size": project_fm.MEMORY_MIN_VALUE, - "code_type": "package", - "runtime": runtime.id, - "entry": "main.main", - "package_file": temp_file, - }) - - url = reverse('horizon:project:functions:create') - res = self.client.post(url, form_data) - - self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, INDEX_URL) - - # create expected form data. - actual_form_data = copy.deepcopy(form_data) - for k, v in form_data.items(): - if not v: - del actual_form_data[k] - del actual_form_data['code_type'] - del actual_form_data['package_file'] - actual_form_data.update({ - 'package': FILE_CONTENT, - 'code': {'source': 'package', - 'md5sum': calculate_md5(temp_file)} - }) - - qclient.functions.create.\ - assert_called_once_with(**actual_form_data) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_create_package_case_with_least_params( - self, mock_qinlingclient): - """Test create function by package with least parameters""" - self._mock_function_version_list(mock_qinlingclient) - - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = self.functions.first() - qclient.functions.create.return_value = self.functions.first() - qclient.runtimes.list.return_value = self.runtimes.list() - - runtime = self.runtimes.first() - - temp_file = self._create_temp_file() - - form_data = copy.deepcopy(FULL_FORM) - form_data.update({ - "code_type": "package", - "runtime": runtime.id, - "package_file": temp_file, - }) - - url = reverse('horizon:project:functions:create') - res = self.client.post(url, form_data) - - self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, INDEX_URL) - - # create expected form data. - actual_form_data = copy.deepcopy(form_data) - for k, v in form_data.items(): - if not v: - del actual_form_data[k] - del actual_form_data['code_type'] - del actual_form_data['package_file'] - actual_form_data.update({ - 'package': FILE_CONTENT, - 'code': {'source': 'package', - 'md5sum': calculate_md5(temp_file)} - }) - - qclient.functions.create.\ - assert_called_once_with(**actual_form_data) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_create_package_case_no_package_file_specified( - self, mock_qinlingclient): - """Error case of function creation from package - - Because no package_file is specified - """ - delete_key = ['package_file'] - message = 'You must specify package file.' - self._function_create_package_case_error(mock_qinlingclient, - delete_key, - message) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_create_package_case_no_runtime_specified( - self, mock_qinlingclient): - """Error case of function creation from package - - Because no runtime is specified - """ - delete_key = ['runtime'] - message = 'You must specify runtime.' - self._function_create_package_case_error(mock_qinlingclient, - delete_key, - message) - - def _function_create_package_case_error( - self, mock_qinlingclient, delete_key=None, message=''): - """Base function for testing function creation from package""" - if not delete_key: - delete_key = [] - - self._mock_function_version_list(mock_qinlingclient) - - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = self.functions.first() - qclient.functions.create.return_value = self.functions.first() - qclient.runtimes.list.return_value = self.runtimes.list() - - temp_file = self._create_temp_file() - - form_data = copy.deepcopy(FULL_FORM) - form_data.update({ - "name": "test_name", - "description": "description", - "cpu": project_fm.CPU_MIN_VALUE, - "memory_size": project_fm.MEMORY_MIN_VALUE, - "code_type": "package", - "entry": "main.main", - "package_file": temp_file, - }) - - for k in delete_key: - if k in form_data: - del form_data[k] - - url = reverse('horizon:project:functions:create') - res = self.client.post(url, form_data) - - self.assertContains(res, message) - qclient.functions.create.assert_not_called() - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_version_delete(self, mock_qinlingclient): - """Test function version delete""" - function_id = self.functions.first().id - version_id = self.versions.first().id - version_number = self.versions.first().version_number - - self._mock_function_version_list(mock_qinlingclient) - - qclient = mock_qinlingclient.return_value - qclient.function_versions.delete.return_value = None - - url = reverse('horizon:project:functions:detail', args=[function_id]) - url += '?tab=function_details__versions_of_this_function' - - form_data = {'action': 'function_versions__delete__%s' % version_id} - res = self.client.post(url, form_data) - - self.assertRedirectsNoFollow(res, url) - - qclient.function_versions.delete.\ - assert_called_once_with(function_id, version_number) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_version_create(self, mock_qinlingclient): - """Test function version create""" - self._mock_function_version_list(mock_qinlingclient) - - function_id = self.functions.first().id - - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = self.functions.first() - - description_data = 'some description' - form_data = {'function_id': function_id, - 'description': description_data} - - url = reverse('horizon:project:functions:create_version', - args=[function_id]) - res = self.client.post(url, form_data) - - self.assertNoFormErrors(res) - - create_version_success_url = \ - reverse('horizon:project:functions:detail', args=[function_id]) - create_version_success_url += '?tab=function_details__' \ - 'versions_of_this_function' - self.assertRedirectsNoFollow(res, create_version_success_url) - - qclient.function_versions.create.\ - assert_called_once_with(function_id, description_data) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_download(self, mock_qinlingclient): - """Test function download""" - self._mock_function_version_list(mock_qinlingclient) - - function_id = self.functions.first().id - - qclient = mock_qinlingclient.return_value - - qclient.functions.get.return_value = \ - response.HttpResponse(content="DUMMY_DOWNLOAD_DATA") - - url = reverse('horizon:project:functions:download', args=[function_id]) - res = self.client.get(url) - - # res._headers[content-disposition] will be set like - # ('Content-Disposition', - # 'attachment; filename=qinling-function-.zip') - result_header = res._headers['content-disposition'][1] - - expected_header = \ - 'attachment; filename=qinling-function-%s.zip' % function_id - self.assertEqual(result_header, expected_header) - qclient.functions.get.assert_called_once_with(function_id, - download=True) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_function_delete(self, mock_qinlingclient): - """Test function delete""" - function_id = self.functions.first().id - - self._mock_function_version_list(mock_qinlingclient) - - qclient = mock_qinlingclient.return_value - qclient.functions.delete.return_value = None - - form_data = {'action': 'functions__delete__%s' % function_id} - res = self.client.post(INDEX_URL, form_data) - self.assertRedirectsNoFollow(res, INDEX_URL) - - qclient.functions.delete.assert_called_once_with(function_id) - - @mock.patch.object(api.qinling, 'qinlingclient') - def test_index(self, mock_qinlingclient): - """Test IndexView""" - qclient = mock_qinlingclient.return_value - - self._mock_function_version_list(mock_qinlingclient) - - res = self.client.get(INDEX_URL) - - self.assertTemplateUsed(res, INDEX_TEMPLATE) - result_functions = res.context['functions_table'].data - api_functions = api.qinling.functions_list(self.request) - - calls = [(), ()] # called twice, without any argument. - self.assertCountEqual(result_functions, api_functions) - qclient.functions.list.assert_has_calls(calls) - - @test.create_mocks({ - api.qinling: [ - 'functions_list', - ]}) - def test_index_functions_list_returns_exception(self): - """Test IndexView with exception from functions list""" - - self.mock_functions_list.side_effect = self.exceptions.qinling - - res = self.client.get(INDEX_URL) - - self.assertTemplateUsed(res, INDEX_TEMPLATE) - - self.assertEqual(len(res.context['functions_table'].data), 0) - self.assertMessageCount(res, error=1) - - self.mock_functions_list.assert_has_calls( - [ - mock.call(test.IsHttpRequest()), - ]) - - # Do not mock function_get directly to call set_code - # so that function.code is converted into dict correctly. - @mock.patch.object(api.qinling, 'qinlingclient') - def test_detail(self, mock_qinlingclient): - """Test DetailView""" - function_id = self.functions.first().id - qclient = mock_qinlingclient.return_value - qclient.functions.get.return_value = self.functions.first() - - url = urlunquote(reverse('horizon:project:functions:detail', - args=[function_id])) - res = self.client.get(url) - - result_function = res.context['function'] - - self.assertEqual(function_id, result_function.id) - - self.assertTemplateUsed(res, 'project/functions/detail.html') - qclient.functions.get.assert_called_once_with(function_id) - - @test.create_mocks({ - api.qinling: [ - 'function_get', - ]}) - def test_detail_function_get_returns_exception(self): - """Test DetailView with exception from function get""" - function_id = self.functions.first().id - self.mock_function_get.side_effect = self.exceptions.qinling - - url = urlunquote(reverse('horizon:project:functions:detail', - args=[function_id])) - - res = self.client.get(url) - - redir_url = INDEX_URL - self.assertRedirectsNoFollow(res, redir_url) - - self.mock_function_get.assert_has_calls( - [ - mock.call(test.IsHttpRequest(), function_id), - ]) - - # Do not mock function_get directly to call set_code - # so that function.code is converted into dict correctly. - @mock.patch.object(api.qinling, 'qinlingclient') - def test_detail_executions_tab(self, mock_qinlingclient): - data_executions = self.executions.list() - data_function = self.functions.first() - function_id = data_function.id - - my_executions = [ex for ex in data_executions - if ex.function_id == function_id] - - qclient = mock_qinlingclient.return_value - qclient.function_executions.list.return_value = my_executions - qclient.functions.get.return_value = data_function - - url_base = 'horizon:project:functions:detail_executions' - url = urlunquote(reverse(url_base, args=[function_id])) - res = self.client.get(url) - - result_executions = res.context['function_executions_table'].data - - self.assertTemplateUsed(res, 'project/functions/detail.html') - self.assertEqual(my_executions, result_executions) - - qclient.functions.get.assert_called_once_with(function_id) - - calls = [mock.call(), - mock.call()] - qclient.function_executions.list.assert_has_calls(calls) - - # Do not mock function_get directly to call set_code - # so that function.code is converted into dict correctly. - @mock.patch.object(api.qinling, 'qinlingclient') - def test_detail_executions_tab_executions_list_returns_exception( - self, mock_qinlingclient): - data_function = self.functions.first() - function_id = data_function.id - - qclient = mock_qinlingclient.return_value - qclient.function_executions.list.side_effect = self.exceptions.qinling - qclient.functions.get.return_value = data_function - - url_base = 'horizon:project:functions:detail_executions' - url = urlunquote(reverse(url_base, args=[function_id])) - res = self.client.get(url) - - result_executions = res.context['function_executions_table'].data - - self.assertTemplateUsed(res, 'project/functions/detail.html') - self.assertEqual(len(result_executions), 0) - - qclient.functions.get.assert_called_once_with(function_id) - - calls = [mock.call(), - mock.call()] - qclient.function_executions.list.assert_has_calls(calls) - - # Do not mock function_get directly to call set_code - # so that function.code is converted into dict correctly. - @mock.patch.object(api.qinling, 'qinlingclient') - def test_detail_versions_tab(self, mock_qinlingclient): - data_versions = self.versions.list() - data_function = self.functions.first() - function_id = data_function.id - - my_versions = [v for v in data_versions - if v.function_id == function_id] - - qclient = mock_qinlingclient.return_value - qclient.function_versions.list.return_value = my_versions - qclient.functions.get.return_value = data_function - - url_base = 'horizon:project:functions:detail_executions' - url = urlunquote(reverse(url_base, args=[function_id])) - res = self.client.get(url) - - result_versions = res.context['function_versions_table'].data - - self.assertTemplateUsed(res, 'project/functions/detail.html') - self.assertEqual(my_versions, result_versions) - - qclient.functions.get.assert_called_once_with(function_id) - - calls = [mock.call(function_id,), - mock.call(function_id,)] - qclient.function_versions.list.assert_has_calls(calls) - - # Do not mock function_get directly to call set_code - # so that function.code is converted into dict correctly. - @mock.patch.object(api.qinling, 'qinlingclient') - def test_detail_versions_tab_versions_list_returns_exception( - self, mock_qinlingclient): - data_function = self.functions.first() - function_id = data_function.id - - qclient = mock_qinlingclient.return_value - qclient.function_versions.list.side_effect = self.exceptions.qinling - qclient.functions.get.return_value = data_function - - url_base = 'horizon:project:functions:detail_executions' - url = urlunquote(reverse(url_base, args=[function_id])) - res = self.client.get(url) - - result_versions = res.context['function_versions_table'].data - self.assertEqual(len(result_versions), 0) - - self.assertTemplateUsed(res, 'project/functions/detail.html') - - qclient.functions.get.assert_called_once_with(function_id) - - calls = [mock.call(function_id,), - mock.call(function_id,)] - qclient.function_versions.list.assert_has_calls(calls) - - @test.create_mocks({ - api.qinling: [ - 'version_get', - 'versions_list', - ]}) - def test_version_detail(self): - function_id = self.functions.first().id - - data_versions = self.versions.list() - version_number = 1 - data_version = [v for v in data_versions - if v.function_id == function_id and - v.version_number == version_number][0] - - self.mock_version_get.return_value = data_version - self.mock_versions_list.return_value = data_versions - - url = urlunquote(reverse('horizon:project:functions:version_detail', - args=[function_id, version_number])) - res = self.client.get(url) - - result_version = res.context['version'] - - self.assertEqual(version_number, result_version.version_number) - - self.assertTemplateUsed(res, 'project/functions/detail_version.html') - - self.mock_version_get.assert_has_calls( - [ - mock.call(test.IsHttpRequest(), function_id, version_number), - ]) diff --git a/qinling_dashboard/test/tests/content/test_runtimes.py b/qinling_dashboard/test/tests/content/test_runtimes.py deleted file mode 100644 index 21c7d54..0000000 --- a/qinling_dashboard/test/tests/content/test_runtimes.py +++ /dev/null @@ -1,157 +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. - -from unittest import mock - -from django.urls import reverse -from django.utils.http import urlunquote - -from qinling_dashboard import api -from qinling_dashboard.test import helpers as test - - -INDEX_TEMPLATE = 'horizon/common/_data_table_view.html' -INDEX_URL = reverse('horizon:project:runtimes:index') - - -class RuntimesTests(test.TestCase): - - @test.create_mocks({ - api.qinling: [ - 'runtime_create', - ]}) - def test_execution_create_with_maximum_params(self): - data_runtime = self.runtimes.first() - - self.mock_runtime_create.return_value = data_runtime - - image_name = 'dummy/dockerimage' - form_data = {'image': image_name, - 'name': 'test_name', - 'description': 'description', - 'untrusted': 'on'} - - url = reverse('horizon:project:runtimes:create') - res = self.client.post(url, form_data) - - self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, INDEX_URL) - - self.mock_runtime_create.assert_called_once_with( - test.IsHttpRequest(), - image=image_name, - name='test_name', - description='description', - trusted=False) - - @test.create_mocks({ - api.qinling: [ - 'runtime_create', - ]}) - def test_execution_create_with_minimum_params(self): - data_runtime = self.runtimes.first() - - self.mock_runtime_create.return_value = data_runtime - - image_name = 'dummy/dockerimage' - form_data = {'image': image_name} - - url = reverse('horizon:project:runtimes:create') - res = self.client.post(url, form_data) - - self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, INDEX_URL) - - self.mock_runtime_create.assert_called_once_with( - test.IsHttpRequest(), image=image_name) - - @test.create_mocks({ - api.qinling: [ - 'runtimes_list', - ]}) - def test_index(self): - data_runtimes = self.runtimes.list() - self.mock_runtimes_list.return_value = data_runtimes - - res = self.client.get(INDEX_URL) - - self.assertTemplateUsed(res, INDEX_TEMPLATE) - runtimes = res.context['runtimes_table'].data - self.assertCountEqual(runtimes, self.runtimes.list()) - - self.mock_runtimes_list.assert_has_calls( - [ - mock.call(test.IsHttpRequest()), - ]) - - @test.create_mocks({ - api.qinling: [ - 'runtimes_list', - ]}) - def test_index_runtimes_list_returns_exception(self): - self.mock_runtimes_list.side_effect = self.exceptions.qinling - - res = self.client.get(INDEX_URL) - - self.assertTemplateUsed(res, INDEX_TEMPLATE) - - self.assertEqual(len(res.context['runtimes_table'].data), 0) - self.assertMessageCount(res, error=1) - - self.mock_runtimes_list.assert_has_calls( - [ - mock.call(test.IsHttpRequest()), - ]) - - @test.create_mocks({ - api.qinling: [ - 'runtime_get', - ]}) - def test_detail(self): - runtime_id = self.runtimes.first().id - self.mock_runtime_get.return_value = self.runtimes.first() - - url = urlunquote(reverse('horizon:project:runtimes:detail', - args=[runtime_id])) - res = self.client.get(url) - - result_runtime = res.context['runtime'] - - self.assertEqual(runtime_id, result_runtime.id) - - self.assertTemplateUsed(res, 'project/runtimes/detail.html') - - self.mock_runtime_get.assert_has_calls( - [ - mock.call(test.IsHttpRequest(), runtime_id), - ]) - - @test.create_mocks({ - api.qinling: [ - 'runtime_get', - ]}) - def test_detail_runtime_get_returns_exception(self): - runtime_id = self.runtimes.first().id - self.mock_runtime_get.side_effect = self.exceptions.qinling - - url = urlunquote(reverse('horizon:project:runtimes:detail', - args=[runtime_id])) - - res = self.client.get(url) - - redir_url = INDEX_URL - self.assertRedirectsNoFollow(res, redir_url) - - self.mock_runtime_get.assert_has_calls( - [ - mock.call(test.IsHttpRequest(), runtime_id), - ]) diff --git a/qinling_dashboard/test/tests/test_validators.py b/qinling_dashboard/test/tests/test_validators.py deleted file mode 100644 index 3335e73..0000000 --- a/qinling_dashboard/test/tests/test_validators.py +++ /dev/null @@ -1,293 +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 unittest - -from django.core.exceptions import ValidationError - -from qinling_dashboard import validators - - -def provider_validate_key_value_pairs(): - provider = list() - - # blank check - empty_row = [ - # blank string - {'d': u'', 'raise': False}, - # multiple lines consist of blank string - {'d': u'\n\n\n\n\n\n\n\n\n\n\n', 'raise': False}, - # multiple lines consist of blank string + valid row - {'d': u'\n\n\n\n\n\n\n\n\n\n\nkey=value', 'raise': False}, - # multiple lines consist of blank string + valid row - # + multiple lines consist of blank string - {'d': u'\n\n\n\n\n\n\n\n\n\n\nkey=value\n\n', 'raise': False}, - ] - provider += empty_row - - # key part check - - # consist of valid character case - key_check_normal = [ - # lower limit - {'d': u'k=v', 'raise': False}, - # upper limit - {'d': u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345' - u'6789!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstu' - u'vwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;' - u'?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR' - u'STUVWXYZ0123456789!"#$%=v', 'raise': False}, - # upper limit +1 - {'d': u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567' - u'89!"#$%&\'()*+,-./:;?@[\\] ^_`{|}~abcdefghijklmnopqrstuvwxy' - u'zABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@' - u'[\\]^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX' - u'YZ0123456789!"#$%A=v', 'raise': True}, - ] - provider += key_check_normal - - # key has initial blank string - key_check_starts_space = [ - {'d': u' =v', 'raise': True}, - # upper limit - {'d': u' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567' - u'89!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxyz' - u'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@[\\' - u']^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01' - u'23456789!"#$=v', 'raise': True}, - # upper limit + 1 - {'d': u' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678' - u'9!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxyzA' - u'BCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@[\\]' - u'^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012' - u'3456789!"#$A=v', 'raise': True}, - ] - provider += key_check_starts_space - - # key has last blank string - key_check_normal = [ - # upper limit - {'d': u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678' - u'9!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxyzA' - u'BCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@[\\]' - u'^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01' - u'23456789!"#$ =v', 'raise': True}, - # upper limit + 1 - {'d': u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678' - u'9!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxyzA' - u'BCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@[\\]' - u'^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01' - u'23456789!"#$% =v', 'raise': True}, - ] - provider += key_check_normal - - # key has blank string in the middle of it - key_check_middle_space = [ - # upper limit - {'d': u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678' - u'9 !"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxyz' - u'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@[\\' - u']^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01' - u'23456789!"#$=v', 'raise': False}, - # upper limit + 1 - {'d': u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' - u' !"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxyzA' - u'BCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@[\\]' - u'^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012' - u'3456789!"#$A=v', 'raise': True}, - ] - provider += key_check_middle_space - - # check for key part - no_key = [ - {'d': u'=v', 'raise': True}, - ] - provider += no_key - - # equal part check - equal_check = [ - # no equal - {'d': 'key1value1', 'raise': True}, - # multiple equal in it - {'d': 'key=value=key\n', 'raise': True}, - ] - provider += equal_check - - # check for value part - - # consist of valid charcters - value_check_normal = [ - # upper limit - {'d': u'k=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567' - u'89!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxyz' - u'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@[\\' - u']^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01' - u'23456789!"#$%', 'raise': False}, - # upper limit + 1 - {'d': u'k=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567' - u'89!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxyz' - u'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@[\\' - u']^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01' - u'23456789!"#$%A', 'raise': True}, - ] - provider += value_check_normal - - # value has initial blank - value_check_starts_space = [ - {'d': u'k= ', 'raise': True}, - # upper limit - {'d': u'k= abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456' - u'789!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxy' - u'zABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@[' - u'\\]^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' - u'0123456789!"#$', 'raise': True}, - # upper limit + 1 - {'d': u'k= abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456' - u'789!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxy' - u'zABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@[' - u'\\]^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' - u'0123456789!"#$A', 'raise': True}, - ] - provider += value_check_starts_space - - # value has last blank - value_check_normal = [ - # upper limit - {'d': u'k=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456' - u'789!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxy' - u'zABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@' - u'[\\]^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX' - u'YZ0123456789!"#$ ', 'raise': True}, - # upper limit + 1 - {'d': u'k=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456' - u'789!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxy' - u'zABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@' - u'[\\]^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX' - u'YZ0123456789!"#$% ', 'raise': True}, - ] - provider += value_check_normal - - # value has middle blank - value_check_middle_space = [ - # upper limit - {'d': u'k=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345' - u'6789 !"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuv' - u'wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU' - u'VWXYZ0123456789!"#$', 'raise': False}, - # upper limit + 1 - {'d': u'k=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345' - u'6789 !"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuv' - u'wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;?@[\\]^_`{|}~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU' - u'VWXYZ0123456789!"#$A', 'raise': True}, - ] - provider += value_check_middle_space - - # no value is specified - no_value = [ - {'d': u'k=', 'raise': True}, - ] - provider += no_value - - return provider - - -def provider_validate_one_line_string(): - return [ - - # Threshold check for number of charaters - - # lower limit - 1 - {'d': u'', 'raise': True}, - # lower limit - {'d': u'a', 'raise': False}, - # upper limit - {'d': u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVwXYZ012345" - u"6789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrst" - u"uvwxyzABCDEFGHIJKLMNOPQRSTUVwXYZ0123456789!\"#$%&'()*+,-./:" - u";<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP" - u"QRSTUVwXYZ0123456789!\"#", - 'raise': False}, - # upper limit + 1 - {'d': u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVwXYZ012345" - u"6789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrst" - u"uvwxyzABCDEFGHIJKLMNOPQRSTUVwXYZ0123456789!\"#$%&'()*+,-./" - u":;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN" - u"OPQRSTUVwXYZ0123456789!\"#$", - 'raise': True}, - - # initial character is blank - - # lower limit - {'d': u' ', 'raise': True}, - # upper limit - {'d': u" bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVwXYZ01234567" - u"89!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuvwx" - u"yzABCDEFGHIJKLMNOPQRSTUVwXYZ0123456789!\"#$%&'()*+,-./:;<=>?" - u"@[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV" - u"wXYZ0123456789!\"#", - 'raise': True}, - # upper limit + 1 - {'d': u" bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVwXYZ0123456" - u"789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuv" - u"wxyzABCDEFGHIJKLMNOPQRSTUVwXYZ0123456789!\"#$%&'()*+,-./:;<" - u"=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR" - u"STUVwXYZ0123456789!\"#a", - 'raise': True}, - - # last character is blank - - # upper limit - {'d': u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVwXYZ0123456" - u"789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuv" - u"wxyzABCDEFGHIJKLMNOPQRSTUVwXYZ0123456789!\"#$%&'()*+,-./:;<" - u"=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR" - u"STUVwXYZ0123456789!\" """, - 'raise': True}, - # upper limit + 1 - {'d': u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVwXYZ0123456" - u"789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuv" - u"wxyzABCDEFGHIJKLMNOPQRSTUVwXYZ0123456789!\"#$%&'()*+,-./:;<" - u"=>?@[\\]^_`{|}~ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR" - u"STUVwXYZ0123456789!\"# """, - 'raise': True}, - - ] - - -class ValidatorsTests(unittest.TestCase): - - def test_validate_metadata(self, data=provider_validate_key_value_pairs()): - for datum in data: - - d = datum.get('d') - raise_expected = datum.get('raise') - - if raise_expected: - self.assertRaises(ValidationError, - validators.validate_key_value_pairs, d) - else: - self.assertIsNone(validators.validate_key_value_pairs(d)) - - def test_validate_openstack_string( - self, data=provider_validate_one_line_string()): - for datum in data: - - d = datum.get('d') - raise_expected = datum.get('raise') - - if raise_expected: - self.assertRaises(ValidationError, - validators.validate_one_line_string, d) - else: - self.assertIsNone(validators.validate_one_line_string(d)) diff --git a/qinling_dashboard/utils.py b/qinling_dashboard/utils.py deleted file mode 100644 index d5cfa0b..0000000 --- a/qinling_dashboard/utils.py +++ /dev/null @@ -1,79 +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. - -# This file is to be included for configuring application which relates -# to orchestration(Heat) functions. - -import hashlib -import json - -from django.utils.translation import pgettext_lazy - - -def calculate_md5(target): - if not target: - return '' - - md5 = hashlib.md5() - for chunk in target.chunks(): - md5.update(chunk) - - return md5.hexdigest() - - -def convert_raw_input_to_api_format(value): - if value == '': - return None - - value = value.replace('\r\n', '\n') - data = value.split('\n') - input_dict = {} - for datum in data: - if datum == "": - continue - k, v = datum.split('=') - input_dict.update({k: v}) - inp = json.dumps(input_dict) - return inp - - -FUNCTION_ENGINE_STATUS_CHOICES = ( - ("Creating", None), - ("Available", True), - ("Upgrading", True), - ("Error", False), - ("Deleting", None), - ("Running", None), - ("Done", True), - ("Paused", True), - ("Cancelled", True), - ("Success", True), - ("Failed", False), -) - - -FUNCTION_ENGINE_STATUS_DISPLAY_CHOICES = ( - ("creating", pgettext_lazy("current status of runtime", u"Creating")), - ("available", - pgettext_lazy("current status of runtime", u"Available")), - ("upgrading", - pgettext_lazy("current status of runtime", u"Upgrading")), - ("error", pgettext_lazy("current status of runtime", u"Error")), - ("deleting", pgettext_lazy("current status of runtime", u"Deleting")), - ("running", pgettext_lazy("current status of runtime", u"Running")), - ("done", pgettext_lazy("current status of runtime", u"Done")), - ("paused", pgettext_lazy("current status of runtime", u"Paused")), - ("cancelled", - pgettext_lazy("current status of runtime", u"Cancelled")), - ("success", pgettext_lazy("current status of runtime", u"Success")), - ("failed", pgettext_lazy("current status of runtime", u"Failed")), -) diff --git a/qinling_dashboard/validators.py b/qinling_dashboard/validators.py deleted file mode 100644 index b94ed8b..0000000 --- a/qinling_dashboard/validators.py +++ /dev/null @@ -1,77 +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 re - -from django.core.exceptions import ValidationError - -from django.utils.translation import ugettext_lazy as _ - - -STRING_VALIDATE_PATTERN = \ - r"""[a-zA-Z0-9\$\[\]\(\)\{\}\*\+\?\^\s\|\.\-\\\\!#%&'",/:;=<>@_`~]""" - -MAX_LENGTH = 255 - - -def validate_1st_space(value): - """Raise execption if 1st character is blank(space)""" - if re.match(r'^\s', value): - raise ValidationError(_("1st character is not valid.")) - - -def validate_last_space(value): - """Raise execption if last character is blank(space)""" - if re.search(r'\s$', value): - raise ValidationError(_("Last character is not valid.")) - - -def validate_one_line_string(value): - """Validate if invalid charcter is included in value. - - Followings are regarded as valid. - - length <= 255 - - consist of - abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVwXYZ0123456789" - !#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ - """ - base_pattern = STRING_VALIDATE_PATTERN - pattern = '^%s{1,%s}$' % (base_pattern, MAX_LENGTH) - if not re.match(pattern, value): - raise ValidationError(_('Invalid character is used ' - 'or exceeding maximum length.')) - validate_1st_space(value) - validate_last_space(value) - - -def validate_key_value_pairs(value): - """Validation logic for execution input. - - Check if value has u'A=B\r\nC=D...' format. - """ - value = value.replace('\r\n', '\n') - data = value.split('\n') - pattern = '^[^=]+=[^=]+$' - - for datum in data: - # Skip validation if value is blank - if datum == '': - continue - - if re.match(pattern, datum) is None: - raise ValidationError(_('Not key-value pair.')) - - metadata_key, metadata_value = datum.split('=') - - # Check key, value both by using validation logic for one line string. - validate_one_line_string(metadata_key) - validate_one_line_string(metadata_value) diff --git a/releasenotes/notes/.placeholder b/releasenotes/notes/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/notes/drop-py-2-7-83f8eb457524a5e1.yaml b/releasenotes/notes/drop-py-2-7-83f8eb457524a5e1.yaml deleted file mode 100644 index c82ac25..0000000 --- a/releasenotes/notes/drop-py-2-7-83f8eb457524a5e1.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -upgrade: - - | - Python 2.7 support has been dropped. Last release of qinling-dashboard - to support python 2.7 is OpenStack Train. The minimum version of Python now - supported by qinling-dashboard is Python 3.6. diff --git a/releasenotes/source/_static/.placeholder b/releasenotes/source/_static/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/source/_templates/.placeholder b/releasenotes/source/_templates/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py deleted file mode 100644 index 3349d11..0000000 --- a/releasenotes/source/conf.py +++ /dev/null @@ -1,274 +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. - -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'openstackdocstheme', - 'reno.sphinxext', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Qinling Dashboard Release Notes' -copyright = u'2017, OpenStack Foundation' - -# openstackdocstheme options -openstackdocs_repo_name = 'openstack/qinling-dashboard' -openstackdocs_auto_name = False -openstackdocs_use_storyboard = True - -# Release notes are version independent, no need to set version and release -release = '' -version = '' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -# default_role = None - -# 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 - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'native' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'QinlingDashboardReleaseNotesdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'QinlingDashboardReleaseNotes.tex', - u'Qinling Dashboard Release Notes Documentation', - u'OpenStack Foundation', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'QinlingDashboardReleaseNotes', - u'Qinling Dashboard Release Notes Documentation', - [u'OpenStack Foundation'], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'QinlingDashboardReleaseNotes', - u'Qinling Dashboard Release Notes Documentation', - u'OpenStack Foundation', 'QinlingDashboardReleaseNotes', - 'Dashboard for Qinling', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False - -# -- Options for Internationalization output ------------------------------ -locale_dirs = ['locale/'] diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst deleted file mode 100644 index b0d541e..0000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -=============================== -Qinling Dashboard Release Notes -=============================== - -.. toctree:: - :maxdepth: 1 - - unreleased - victoria diff --git a/releasenotes/source/locale/de/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/de/LC_MESSAGES/releasenotes.po deleted file mode 100644 index 2ceb235..0000000 --- a/releasenotes/source/locale/de/LC_MESSAGES/releasenotes.po +++ /dev/null @@ -1,21 +0,0 @@ -# Andreas Jaeger , 2019. #zanata -msgid "" -msgstr "" -"Project-Id-Version: qinling-dashboard\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-09-28 11:28+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2019-09-28 02:22+0000\n" -"Last-Translator: Andreas Jaeger \n" -"Language-Team: German\n" -"Language: de\n" -"X-Generator: Zanata 4.3.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "Current Series Release Notes" -msgstr "Aktuelle Serie Releasenotes" - -msgid "Qinling Dashboard Release Notes" -msgstr "Qinling Dashboard Releasenotes" diff --git a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po deleted file mode 100644 index 993111d..0000000 --- a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po +++ /dev/null @@ -1,22 +0,0 @@ -# Andi Chandler , 2018. #zanata -# Andi Chandler , 2020. #zanata -msgid "" -msgstr "" -"Project-Id-Version: Qinling Dashboard Release Notes\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-09-11 21:48+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2020-06-15 05:41+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en_GB\n" -"X-Generator: Zanata 4.3.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "Current Series Release Notes" -msgstr "Current Series Release Notes" - -msgid "Qinling Dashboard Release Notes" -msgstr "Qinling Dashboard Release Notes" diff --git a/releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po deleted file mode 100644 index ed09acc..0000000 --- a/releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po +++ /dev/null @@ -1,22 +0,0 @@ -# SEEUNG KANG , 2018. #zanata -# Hongjae Kim , 2019. #zanata -msgid "" -msgstr "" -"Project-Id-Version: qinling-dashboard\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-31 02:02+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2019-11-02 09:00+0000\n" -"Last-Translator: Hongjae Kim \n" -"Language-Team: Korean (South Korea)\n" -"Language: ko_KR\n" -"X-Generator: Zanata 4.3.3\n" -"Plural-Forms: nplurals=1; plural=0\n" - -msgid "Current Series Release Notes" -msgstr "최신 시리즈에 대한 릴리즈 노트" - -msgid "Qinling Dashboard Release Notes" -msgstr "Quinling Dashboard 릴리스 노트" diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst deleted file mode 100644 index cd22aab..0000000 --- a/releasenotes/source/unreleased.rst +++ /dev/null @@ -1,5 +0,0 @@ -============================== - Current Series Release Notes -============================== - -.. release-notes:: diff --git a/releasenotes/source/victoria.rst b/releasenotes/source/victoria.rst deleted file mode 100644 index 4efc7b6..0000000 --- a/releasenotes/source/victoria.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================= -Victoria Series Release Notes -============================= - -.. release-notes:: - :branch: stable/victoria diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 54d9d28..0000000 --- a/requirements.txt +++ /dev/null @@ -1,15 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -# Order matters to the pip dependency resolver, so sorting this file -# changes how packages are installed. New dependencies should be -# added in alphabetical order, however, some dependencies may need to -# be installed in a specific order. -# -# PBR should always appear first -pbr!=2.1.0,>=2.0.0 # Apache-2.0 -python-qinlingclient>=1.1.0 # Apache-2.0 - -# This will be installed from git in OpenStack CI if the job setting -# required-projects for horizon: -horizon>=17.1.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index e93a8fe..0000000 --- a/setup.cfg +++ /dev/null @@ -1,25 +0,0 @@ -[metadata] -name = qinling-dashboard -summary = Qinling Management Dashboard -description-file = - README.rst -author = OpenStack -author-email = openstack-discuss@lists.openstack.org -home-page = https://docs.openstack.org/qinling-dashboard/latest/ -python-requires = >=3.6 -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 :: Implementation :: CPython - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 - -[files] -packages = - qinling_dashboard diff --git a/setup.py b/setup.py deleted file mode 100644 index cd35c3c..0000000 --- a/setup.py +++ /dev/null @@ -1,20 +0,0 @@ -# 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 setuptools - -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 611f5e2..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,21 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -# Order matters to the pip dependency resolver, so sorting this file -# changes how packages are installed. New dependencies should be -# added in alphabetical order, however, some dependencies may need to -# be installed in a specific order. -# -# Hacking should appear first in case something else depends on pep8 -hacking>=3.0,<3.1.0 # Apache-2.0 -# -coverage!=4.4,>=4.0 # Apache-2.0 -django-nose>=1.4.4 # BSD -doc8>=0.6.0 # Apache-2.0 -flake8-import-order==0.12 # LGPLv3 -nose>=1.3.7 # LGPL -nose-exclude>=0.3.0 # LGPL -nosehtmloutput>=0.0.3 # Apache-2.0 -nosexcover>=1.0.10 # BSD -openstack.nose-plugin>=0.7 # Apache-2.0 -testtools>=2.2.0 # MIT diff --git a/tox.ini b/tox.ini deleted file mode 100644 index b79d1b6..0000000 --- a/tox.ini +++ /dev/null @@ -1,81 +0,0 @@ -[tox] -envlist = py37,pep8,docs -minversion = 2.3.2 -skipsdist = True - -[testenv] -usedevelop = True -basepython = python3 -setenv = - VIRTUAL_ENV={envdir} - INTEGRATION_TESTS=0 - NOSE_WITH_OPENSTACK=1 - NOSE_OPENSTACK_COLOR=1 - NOSE_OPENSTACK_RED=0.05 - NOSE_OPENSTACK_YELLOW=0.025 - NOSE_OPENSTACK_SHOW_ELAPSED=1 -deps = -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} - -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = - pip install -r requirements.txt - python manage.py test qinling_dashboard.test --settings=qinling_dashboard.test.settings - -[testenv:pep8] -commands = flake8 {posargs} - -[testenv:venv] -commands = {posargs} - -[testenv:cover] -commands = - coverage erase - coverage run --source=qinling_dashboard {toxinidir}/manage.py test qinling_dashboard.test.tests --settings=qinling_dashboard.test.settings {posargs} - coverage xml - coverage html - -[testenv:docs] -deps = -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} - -r{toxinidir}/doc/requirements.txt -commands = - sphinx-build -W -b html doc/source doc/build/html - -[testenv:pdf-docs] -envdir = {toxworkdir}/docs -deps = {[testenv:docs]deps} -whitelist_externals = - make -commands = - sphinx-build -W -b latex doc/source doc/build/pdf - make -C doc/build/pdf - -[testenv:releasenotes] -deps = -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} - -r{toxinidir}/doc/requirements.txt -commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html - -[flake8] -exclude = .venv,.git,.tox,dist,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py,*/local/*,*/test/test_plugins/*,.ropeproject,node_modules,.tmp -max-complexity = 20 -import-order-style = pep8 - -[flake8:local-plugins] -extension = - M322 = horizon.hacking.checks:no_mutable_default_args - -[doc8] -# File extensions to check -extensions = .rst, .yaml -# Maximal line length should be 80 but we have some overlong lines. -# Let's not get far more in. -max-line-length = 80 -# Disable some doc8 checks: -# D000: Check RST validity -# - cannot handle "none" for code-block directive -ignore = D000 - -[testenv:lower-constraints] -deps = - -c{toxinidir}/lower-constraints.txt - -r{toxinidir}/test-requirements.txt - -r{toxinidir}/requirements.txt