From c17cc5beb4f875d1b7b8efef446bcced47f80967 Mon Sep 17 00:00:00 2001 From: Bradley Jones Date: Tue, 11 Aug 2015 21:50:27 +0100 Subject: [PATCH] Initial skeleton repo Add the basic structure for the magnum-ui repository to serve as a starting point for contributions. The structure is likely to change as development progresses. Change-Id: I5458741e2dd4c3409992315efaa60b33824b4ec8 Implements: blueprint repo-skeleton --- .gitignore | 11 + LICENSE | 176 ++++++ MANIFEST.in | 4 + README.rst | 51 ++ doc/Makefile | 153 +++++ doc/source/conf.py | 439 +++++++++++++ doc/source/index.rst | 64 ++ doc/source/releases/0.1.0.rst | 2 + enabled/_50_add_containers_dashboard.py | 26 + magnum_ui/__init__.py | 0 magnum_ui/api/__init__.py | 0 magnum_ui/babel-django.cfg | 5 + magnum_ui/babel-djangojs.cfg | 14 + magnum_ui/bay/__init__.py | 0 magnum_ui/bay/panel.py | 26 + magnum_ui/bay/templates/bay/index.html | 10 + magnum_ui/bay/tests.py | 21 + magnum_ui/bay/urls.py | 24 + magnum_ui/bay/views.py | 20 + magnum_ui/baymodel/__init__.py | 0 magnum_ui/baymodel/panel.py | 26 + .../baymodel/templates/baymodel/index.html | 10 + magnum_ui/baymodel/tests.py | 21 + magnum_ui/baymodel/urls.py | 24 + magnum_ui/baymodel/views.py | 20 + magnum_ui/dashboard.py | 26 + magnum_ui/locale/django.pot | 31 + magnum_ui/locale/djangojs.pot | 19 + magnum_ui/models.py | 3 + .../dashboard/containers/bay/bay.module.js | 31 + .../containers/bay/bay.module.spec.js | 25 + .../static/dashboard/containers/bay/bay.scss | 0 .../containers/baymodel/baymodel.module.js | 31 + .../baymodel/baymodel.module.spec.js | 25 + .../containers/baymodel/baymodel.scss | 0 .../dashboard/containers/containers.module.js | 33 + .../containers/containers.module.spec.js | 25 + .../dashboard/containers/containers.scss | 9 + magnum_ui/test/__init__.py | 0 magnum_ui/test/integration_tests/__init__.py | 0 magnum_ui/version.py | 3 + manage.py | 23 + requirements.txt | 39 ++ run_tests.sh | 583 ++++++++++++++++++ setup.cfg | 26 + setup.py | 30 + test-requirements.txt | 29 + tools/install_venv.py | 71 +++ tools/with_venv.sh | 7 + tox.ini | 87 +++ 50 files changed, 2303 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 MANIFEST.in create mode 100644 README.rst create mode 100644 doc/Makefile create mode 100644 doc/source/conf.py create mode 100644 doc/source/index.rst create mode 100644 doc/source/releases/0.1.0.rst create mode 100644 enabled/_50_add_containers_dashboard.py create mode 100644 magnum_ui/__init__.py create mode 100644 magnum_ui/api/__init__.py create mode 100644 magnum_ui/babel-django.cfg create mode 100644 magnum_ui/babel-djangojs.cfg create mode 100644 magnum_ui/bay/__init__.py create mode 100644 magnum_ui/bay/panel.py create mode 100644 magnum_ui/bay/templates/bay/index.html create mode 100644 magnum_ui/bay/tests.py create mode 100644 magnum_ui/bay/urls.py create mode 100644 magnum_ui/bay/views.py create mode 100644 magnum_ui/baymodel/__init__.py create mode 100644 magnum_ui/baymodel/panel.py create mode 100644 magnum_ui/baymodel/templates/baymodel/index.html create mode 100644 magnum_ui/baymodel/tests.py create mode 100644 magnum_ui/baymodel/urls.py create mode 100644 magnum_ui/baymodel/views.py create mode 100644 magnum_ui/dashboard.py create mode 100644 magnum_ui/locale/django.pot create mode 100644 magnum_ui/locale/djangojs.pot create mode 100644 magnum_ui/models.py create mode 100644 magnum_ui/static/dashboard/containers/bay/bay.module.js create mode 100644 magnum_ui/static/dashboard/containers/bay/bay.module.spec.js create mode 100644 magnum_ui/static/dashboard/containers/bay/bay.scss create mode 100644 magnum_ui/static/dashboard/containers/baymodel/baymodel.module.js create mode 100644 magnum_ui/static/dashboard/containers/baymodel/baymodel.module.spec.js create mode 100644 magnum_ui/static/dashboard/containers/baymodel/baymodel.scss create mode 100644 magnum_ui/static/dashboard/containers/containers.module.js create mode 100644 magnum_ui/static/dashboard/containers/containers.module.spec.js create mode 100644 magnum_ui/static/dashboard/containers/containers.scss create mode 100644 magnum_ui/test/__init__.py create mode 100644 magnum_ui/test/integration_tests/__init__.py create mode 100644 magnum_ui/version.py create mode 100755 manage.py create mode 100644 requirements.txt create mode 100755 run_tests.sh create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 test-requirements.txt create mode 100644 tools/install_venv.py create mode 100755 tools/with_venv.sh create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..59d7bf46 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +AUTHORS +ChangeLog +build +doc/source/sourcecode +magnum_ui/test/.secret_key_store +.venv +.tox +*.pyc +*.lock +*.egg* +*.swp diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..68c771a0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,176 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..885c1393 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,4 @@ +include setup.py +recursive-include magnum_ui/bay/templates * +recursive-include magnum_ui/baymodel/templates * +recursive-include magnum_ui/static * diff --git a/README.rst b/README.rst new file mode 100644 index 00000000..23ae6cdb --- /dev/null +++ b/README.rst @@ -0,0 +1,51 @@ +=============================== +magnum-ui +=============================== + +Magnum Dashboard + +* Free software: Apache license +* Source: http://git.openstack.org/cgit/openstack/magnum-ui +* Bugs: http://bugs.launchpad.net/magnum-ui + +Installation instructions +------------------------- + +Begin by cloning the Horizon and Magnum UI repositories:: + + git clone https://github.com/openstack/horizon + git clone https://github.com/openstack/magnum-ui + +Create a virtual environment and install Horizon dependencies:: + + cd horizon + python tools/install_venv.py + +Set up your ``local_settings.py`` file:: + + cp openstack_dashboard/local/local_settings.py.example openstack_dashboard/local/local_settings.py + +Open up the copied ``local_settings.py`` file in your preferred text +editor. You will want to customize several settings: + +- ``OPENSTACK_HOST`` should be configured with the hostname of your + OpenStack server. Verify that the ``OPENSTACK_KEYSTONE_URL`` and + ``OPENSTACK_KEYSTONE_DEFAULT_ROLE`` settings are correct for your + environment. (They should be correct unless you modified your + OpenStack server to change them.) + + +Install Magnum UI with all dependencies in your virtual environment:: + + tools/with_venv.sh pip install -e ../magnum-ui/ + +And enable it in Horizon:: + + cp ../magnum-ui/enabled/_50_add_containers_dashboard.py openstack_dashboard/local/enabled + +To run horizon with the newly enabled Magnum UI plugin run:: + + ./run_tests.sh --runserver 0.0.0.0:8080 + +to have the application start on port 8080 and the horizon dashboard will be +available in your browser at http://localhost:8080/ diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 00000000..efaeb8e9 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Cisco.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Cisco.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Cisco" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Cisco" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/doc/source/conf.py b/doc/source/conf.py new file mode 100644 index 00000000..9ff10771 --- /dev/null +++ b/doc/source/conf.py @@ -0,0 +1,439 @@ +# 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. +# +# Horizon documentation build configuration file, created by +# sphinx-quickstart on Thu Oct 27 11:38:59 2011. +# +# 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. + +from __future__ import print_function + +import os +import sys + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +ROOT = os.path.abspath(os.path.join(BASE_DIR, "..", "..")) + +sys.path.insert(0, ROOT) + +# This is required for ReadTheDocs.org, but isn't a bad idea anyway. +os.environ.setdefault('DJANGO_SETTINGS_MODULE', + 'magnum_ui.test.settings') + +from magnum_ui \ + import version as magnumui_ver + + +def write_autodoc_index(): + + def find_autodoc_modules(module_name, sourcedir): + """returns a list of modules in the SOURCE directory.""" + modlist = [] + os.chdir(os.path.join(sourcedir, module_name)) + print("SEARCHING %s" % sourcedir) + for root, dirs, files in os.walk("."): + for filename in files: + if filename == 'tests.py': + continue + if filename.endswith(".py"): + # remove the pieces of the root + elements = root.split(os.path.sep) + # replace the leading "." with the module name + elements[0] = module_name + # and get the base module name + base, extension = os.path.splitext(filename) + if not (base == "__init__"): + elements.append(base) + result = ".".join(elements) + # print result + modlist.append(result) + return modlist + + RSTDIR = os.path.abspath(os.path.join(BASE_DIR, "sourcecode")) + SRCS = [('magnum_ui', ROOT), ] + + EXCLUDED_MODULES = () + CURRENT_SOURCES = {} + + if not(os.path.exists(RSTDIR)): + os.mkdir(RSTDIR) + CURRENT_SOURCES[RSTDIR] = ['autoindex.rst'] + + INDEXOUT = open(os.path.join(RSTDIR, "autoindex.rst"), "w") + INDEXOUT.write(""" +================= +Source Code Index +================= + +.. contents:: + :depth: 1 + :local: + +""") + + for modulename, path in SRCS: + sys.stdout.write("Generating source documentation for %s\n" % + modulename) + INDEXOUT.write("\n%s\n" % modulename.capitalize()) + INDEXOUT.write("%s\n" % ("=" * len(modulename),)) + INDEXOUT.write(".. toctree::\n") + INDEXOUT.write(" :maxdepth: 1\n") + INDEXOUT.write("\n") + + MOD_DIR = os.path.join(RSTDIR, modulename) + CURRENT_SOURCES[MOD_DIR] = [] + if not(os.path.exists(MOD_DIR)): + os.mkdir(MOD_DIR) + for module in find_autodoc_modules(modulename, path): + if any([module.startswith(exclude) for exclude + in EXCLUDED_MODULES]): + print("Excluded module %s." % module) + continue + mod_path = os.path.join(path, *module.split(".")) + generated_file = os.path.join(MOD_DIR, "%s.rst" % module) + + INDEXOUT.write(" %s/%s\n" % (modulename, module)) + + # Find the __init__.py module if this is a directory + if os.path.isdir(mod_path): + source_file = ".".join((os.path.join(mod_path, "__init__"), + "py",)) + else: + source_file = ".".join((os.path.join(mod_path), "py")) + + CURRENT_SOURCES[MOD_DIR].append("%s.rst" % module) + # Only generate a new file if the source has changed or we don't + # have a doc file to begin with. + if not os.access(generated_file, os.F_OK) or ( + os.stat(generated_file).st_mtime < + os.stat(source_file).st_mtime): + print("Module %s updated, generating new documentation." + % module) + FILEOUT = open(generated_file, "w") + header = "The :mod:`%s` Module" % module + FILEOUT.write("%s\n" % ("=" * len(header),)) + FILEOUT.write("%s\n" % header) + FILEOUT.write("%s\n" % ("=" * len(header),)) + FILEOUT.write(".. automodule:: %s\n" % module) + FILEOUT.write(" :members:\n") + FILEOUT.write(" :undoc-members:\n") + FILEOUT.write(" :show-inheritance:\n") + FILEOUT.write(" :noindex:\n") + FILEOUT.close() + + INDEXOUT.close() + + # Delete auto-generated .rst files for sources which no longer exist + for directory, subdirs, files in list(os.walk(RSTDIR)): + for old_file in files: + if old_file not in CURRENT_SOURCES.get(directory, []): + print("Removing outdated file for %s" % old_file) + os.remove(os.path.join(directory, old_file)) + + +write_autodoc_index() + +# 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 = ['sphinx.ext.autodoc', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.pngmath', + 'sphinx.ext.viewcode', + 'oslosphinx', + ] + +# 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'Magnum UI' +copyright = u'2015, Cisco Systems, Inc.' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = magnumui_ver.version_info.version_string() +# The full version, including alpha/beta/rc tags. +release = magnumui_ver.version_info.release_string() + +# 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 = 'sphinx' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +primary_domain = 'py' +nitpicky = 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_path = ['.'] +# html_theme = '_theme' + +# 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 = { + "nosidebar": "false" +} + +# 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'] + +# 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' +git_cmd = "git log --pretty=format:'%ad, commit %h' --date=local -n1" +html_last_updated_fmt = os.popen(git_cmd).read() + +# 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 = 'Horizondoc' + + +# -- 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]). +latex_documents = [ + ('index', 'Horizon.tex', u'Horizon 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', u'Magnum UI Documentation', + 'Documentation for the Magnum UI plugin to the Openstack\ + Dashboard (Horizon)', + [u'OpenStack'], 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', 'Horizon', u'Horizon Documentation', u'OpenStack', + 'Horizon', 'One line description of project.', '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' + + +# -- Options for Epub output -------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = u'Horizon' +epub_author = u'OpenStack' +epub_publisher = u'OpenStack' +epub_copyright = u'2012, OpenStack' + +# The language of the text. It defaults to the language option +# or en if the language is not set. +# epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +# epub_scheme = '' + +# The unique identifier of the text. This can be an ISBN number +# or the project homepage. +# epub_identifier = '' + +# A unique identification for the text. +# epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +# epub_cover = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +# epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +# epub_post_files = [] + +# A list of files that should not be packed into the epub file. +# epub_exclude_files = [] + +# The depth of the table of contents in toc.ncx. +# epub_tocdepth = 3 + +# Allow duplicate toc entries. +# epub_tocdup = True diff --git a/doc/source/index.rst b/doc/source/index.rst new file mode 100644 index 00000000..e302dd1f --- /dev/null +++ b/doc/source/index.rst @@ -0,0 +1,64 @@ +=============================== +magnum-ui +=============================== + +Magnum Dashboard + +* Free software: Apache license +* Source: http://git.openstack.org/cgit/openstack/magnum-ui +* Bugs: http://bugs.launchpad.net/magnum-ui + +Installation instructions +========================= + +Begin by cloning the Horizon and Magnum UI repositories:: + + git clone https://github.com/openstack/horizon + git clone https://github.com/openstack/magnum-ui + +Create a virtual environment and install Horizon dependencies:: + + cd horizon + python tools/install_venv.py + +Set up your ``local_settings.py`` file:: + + cp openstack_dashboard/local/local_settings.py.example openstack_dashboard/local/local_settings.py + +Open up the copied ``local_settings.py`` file in your preferred text +editor. You will want to customize several settings: + +- ``OPENSTACK_HOST`` should be configured with the hostname of your + OpenStack server. Verify that the ``OPENSTACK_KEYSTONE_URL`` and + ``OPENSTACK_KEYSTONE_DEFAULT_ROLE`` settings are correct for your + environment. (They should be correct unless you modified your + OpenStack server to change them.) + + +Install Magnum UI with all dependencies in your virtual environment:: + + tools/with_venv.sh pip install -e ../magnum-ui/ + +And enable it in Horizon:: + + cp ../magnum-ui/enabled/_50_add_containers_dashboard.py openstack_dashboard/local/enabled + +Release Notes +============= + +.. toctree:: + :glob: + :maxdepth: 1 + + releases/* + +Source Code Reference +===================== + +.. toctree:: + :glob: + :maxdepth: 1 + + sourcecode/autoindex + + diff --git a/doc/source/releases/0.1.0.rst b/doc/source/releases/0.1.0.rst new file mode 100644 index 00000000..309e705e --- /dev/null +++ b/doc/source/releases/0.1.0.rst @@ -0,0 +1,2 @@ +Magnum UI 0.1.0 +=============== diff --git a/enabled/_50_add_containers_dashboard.py b/enabled/_50_add_containers_dashboard.py new file mode 100644 index 00000000..178d5463 --- /dev/null +++ b/enabled/_50_add_containers_dashboard.py @@ -0,0 +1,26 @@ +# Copyright 2015 Cisco Systems. +# +# 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. + +DASHBOARD = 'containers' +ADD_INSTALLED_APPS = ['magnum_ui'] + +ADD_ANGULAR_MODULES = [ + 'horizon.dashboard.containers' +] + +ADD_SCSS_FILES = [ + 'dashboard/containers/containers.scss' +] + +AUTO_DISCOVER_STATIC_FILES = True diff --git a/magnum_ui/__init__.py b/magnum_ui/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/magnum_ui/api/__init__.py b/magnum_ui/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/magnum_ui/babel-django.cfg b/magnum_ui/babel-django.cfg new file mode 100644 index 00000000..ad09d34b --- /dev/null +++ b/magnum_ui/babel-django.cfg @@ -0,0 +1,5 @@ +[extractors] +django = django_babel.extract:extract_django + +[python: **.py] +[django: templates/**.html] diff --git a/magnum_ui/babel-djangojs.cfg b/magnum_ui/babel-djangojs.cfg new file mode 100644 index 00000000..a8273b62 --- /dev/null +++ b/magnum_ui/babel-djangojs.cfg @@ -0,0 +1,14 @@ +[extractors] +# We use a custom extractor to find translatable strings in AngularJS +# templates. The extractor is included in horizon.utils for now. +# See http://babel.pocoo.org/docs/messages/#referencing-extraction-methods for +# details on how this works. +angular = horizon.utils.babel_extract_angular:extract_angular + +[javascript: **.js] + +# We need to look into all static folders for HTML files. +# The **/static ensures that we also search within +# /openstack_dashboard/dashboards/XYZ/static which will ensure +# that plugins are also translated. +[angular: **/static/**.html] diff --git a/magnum_ui/bay/__init__.py b/magnum_ui/bay/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/magnum_ui/bay/panel.py b/magnum_ui/bay/panel.py new file mode 100644 index 00000000..41322cf5 --- /dev/null +++ b/magnum_ui/bay/panel.py @@ -0,0 +1,26 @@ +# Copyright 2015 Cisco Systems +# +# 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 magnum_ui import dashboard + +import horizon + + +class Bay(horizon.Panel): + name = _("Bays") + slug = "bay" + + +dashboard.Containers.register(Bay) diff --git a/magnum_ui/bay/templates/bay/index.html b/magnum_ui/bay/templates/bay/index.html new file mode 100644 index 00000000..95c949b8 --- /dev/null +++ b/magnum_ui/bay/templates/bay/index.html @@ -0,0 +1,10 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Bays" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Bays") %} +{% endblock page_header %} + +{% block main %} +{% endblock %} diff --git a/magnum_ui/bay/tests.py b/magnum_ui/bay/tests.py new file mode 100644 index 00000000..1b1cbb1c --- /dev/null +++ b/magnum_ui/bay/tests.py @@ -0,0 +1,21 @@ +# Copyright 2015 Cisco Systems +# +# 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 openstack_dashboard.test import helpers as test + + +class BayTests(test.TestCase): + # Unit tests for bay. + def test_me(self): + self.assertTrue(1 + 1 == 2) diff --git a/magnum_ui/bay/urls.py b/magnum_ui/bay/urls.py new file mode 100644 index 00000000..48d5052b --- /dev/null +++ b/magnum_ui/bay/urls.py @@ -0,0 +1,24 @@ +# Copyright 2015 Cisco Systems +# +# 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 patterns +from django.conf.urls import url + +from magnum_ui.bay.views import IndexView + + +urlpatterns = patterns( + '', + url(r'^$', IndexView.as_view(), name='index'), +) diff --git a/magnum_ui/bay/views.py b/magnum_ui/bay/views.py new file mode 100644 index 00000000..1c040ade --- /dev/null +++ b/magnum_ui/bay/views.py @@ -0,0 +1,20 @@ +# Copyright 2015 Cisco Systems +# +# 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 horizon import views + + +class IndexView(views.APIView): + # A very simple class-based view... + template_name = 'containers/bay/index.html' diff --git a/magnum_ui/baymodel/__init__.py b/magnum_ui/baymodel/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/magnum_ui/baymodel/panel.py b/magnum_ui/baymodel/panel.py new file mode 100644 index 00000000..098ad46e --- /dev/null +++ b/magnum_ui/baymodel/panel.py @@ -0,0 +1,26 @@ +# Copyright 2015 Cisco Systems, 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 django.utils.translation import ugettext_lazy as _ +from magnum_ui import dashboard + +import horizon + + +class BayModel(horizon.Panel): + name = _("Bay Models") + slug = "baymodel" + + +dashboard.Containers.register(BayModel) diff --git a/magnum_ui/baymodel/templates/baymodel/index.html b/magnum_ui/baymodel/templates/baymodel/index.html new file mode 100644 index 00000000..0a82613e --- /dev/null +++ b/magnum_ui/baymodel/templates/baymodel/index.html @@ -0,0 +1,10 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Bay Models" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Bay Models") %} +{% endblock page_header %} + +{% block main %} +{% endblock %} diff --git a/magnum_ui/baymodel/tests.py b/magnum_ui/baymodel/tests.py new file mode 100644 index 00000000..ff8adfcb --- /dev/null +++ b/magnum_ui/baymodel/tests.py @@ -0,0 +1,21 @@ +# Copyright 2015 Cisco Systems +# +# 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 openstack_dashboard.test import helpers as test + + +class BayModelTests(test.TestCase): + # Unit tests for bay model. + def test_me(self): + self.assertTrue(1 + 1 == 2) diff --git a/magnum_ui/baymodel/urls.py b/magnum_ui/baymodel/urls.py new file mode 100644 index 00000000..016023bc --- /dev/null +++ b/magnum_ui/baymodel/urls.py @@ -0,0 +1,24 @@ +# Copyright 2015 Cisco Systems +# +# 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 patterns +from django.conf.urls import url + +from magnum_ui.baymodel.views import IndexView + + +urlpatterns = patterns( + '', + url(r'^$', IndexView.as_view(), name='index'), +) diff --git a/magnum_ui/baymodel/views.py b/magnum_ui/baymodel/views.py new file mode 100644 index 00000000..f7f9152b --- /dev/null +++ b/magnum_ui/baymodel/views.py @@ -0,0 +1,20 @@ +# Copyright 2015 Cisco Systems +# +# 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 horizon import views + + +class IndexView(views.APIView): + # A very simple class-based view... + template_name = 'containers/baymodel/index.html' diff --git a/magnum_ui/dashboard.py b/magnum_ui/dashboard.py new file mode 100644 index 00000000..847b2ea7 --- /dev/null +++ b/magnum_ui/dashboard.py @@ -0,0 +1,26 @@ +# Copyright 2015 Cisco Systems. +# +# 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 Containers(horizon.Dashboard): + name = _("Containers") + slug = "containers" + panels = ('bay', 'baymodel') + default_panel = 'bay' + +horizon.register(Containers) diff --git a/magnum_ui/locale/django.pot b/magnum_ui/locale/django.pot new file mode 100644 index 00000000..885da091 --- /dev/null +++ b/magnum_ui/locale/django.pot @@ -0,0 +1,31 @@ +# Translations template for PROJECT. +# Copyright (C) 2015 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2015. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2015-08-12 00:02+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.0\n" + +#: dashboard.py:22 +msgid "Containers" +msgstr "" + +#: bay/panel.py:22 +msgid "Bays" +msgstr "" + +#: bay_model/panel.py:22 +msgid "Bay Models" +msgstr "" + diff --git a/magnum_ui/locale/djangojs.pot b/magnum_ui/locale/djangojs.pot new file mode 100644 index 00000000..fa49ea6a --- /dev/null +++ b/magnum_ui/locale/djangojs.pot @@ -0,0 +1,19 @@ +# Translations template for PROJECT. +# Copyright (C) 2015 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2015. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2015-08-12 00:02+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.0\n" + diff --git a/magnum_ui/models.py b/magnum_ui/models.py new file mode 100644 index 00000000..1b3d5f9e --- /dev/null +++ b/magnum_ui/models.py @@ -0,0 +1,3 @@ +""" +Stub file to work around django bug: https://code.djangoproject.com/ticket/7198 +""" diff --git a/magnum_ui/static/dashboard/containers/bay/bay.module.js b/magnum_ui/static/dashboard/containers/bay/bay.module.js new file mode 100644 index 00000000..962fa2e5 --- /dev/null +++ b/magnum_ui/static/dashboard/containers/bay/bay.module.js @@ -0,0 +1,31 @@ +/** + * Copyright 2015 Cisco Systems, 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. + */ + +(function() { + 'use strict'; + + /** + * @ngdoc overview + * @name horizon.dashboard.containers.bay + * + * @description + * Provides all the services and widgets require to display the bay + * panel + */ + angular + .module('horizon.dashboard.containers.bay', []); + +})(); diff --git a/magnum_ui/static/dashboard/containers/bay/bay.module.spec.js b/magnum_ui/static/dashboard/containers/bay/bay.module.spec.js new file mode 100644 index 00000000..3b2d9968 --- /dev/null +++ b/magnum_ui/static/dashboard/containers/bay/bay.module.spec.js @@ -0,0 +1,25 @@ +/** + * Copyright 2015 Cisco Systems, 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. + */ +(function() { + 'use strict'; + + describe('horizon.dashboard.containers.bay', function() { + it('should exist', function() { + expect(angular.module('horizon.dashboard.containers.bay')).toBeDefined(); + }); + }); + +})(); diff --git a/magnum_ui/static/dashboard/containers/bay/bay.scss b/magnum_ui/static/dashboard/containers/bay/bay.scss new file mode 100644 index 00000000..e69de29b diff --git a/magnum_ui/static/dashboard/containers/baymodel/baymodel.module.js b/magnum_ui/static/dashboard/containers/baymodel/baymodel.module.js new file mode 100644 index 00000000..b1d0966a --- /dev/null +++ b/magnum_ui/static/dashboard/containers/baymodel/baymodel.module.js @@ -0,0 +1,31 @@ +/** + * Copyright 2015 Cisco Systems, 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. + */ + +(function() { + 'use strict'; + + /** + * @ngdoc horizon.dashboard.containers.baymodel + * @ngModule + * + * @description + * Provides all the services and widgets require to display the bay model + * panel + */ + angular + .module('horizon.dashboard.containers.baymodel', []); + +})(); diff --git a/magnum_ui/static/dashboard/containers/baymodel/baymodel.module.spec.js b/magnum_ui/static/dashboard/containers/baymodel/baymodel.module.spec.js new file mode 100644 index 00000000..fce813d7 --- /dev/null +++ b/magnum_ui/static/dashboard/containers/baymodel/baymodel.module.spec.js @@ -0,0 +1,25 @@ +/** + * Copyright 2015 Cisco Systems, 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. + */ +(function() { + 'use strict'; + + describe('horizon.dashboard.containers.baymodel', function() { + it('should exist', function() { + expect(angular.module('horizon.dashboard.containers.baymodel')).toBeDefined(); + }); + }); + +})(); diff --git a/magnum_ui/static/dashboard/containers/baymodel/baymodel.scss b/magnum_ui/static/dashboard/containers/baymodel/baymodel.scss new file mode 100644 index 00000000..e69de29b diff --git a/magnum_ui/static/dashboard/containers/containers.module.js b/magnum_ui/static/dashboard/containers/containers.module.js new file mode 100644 index 00000000..7a9cc6b6 --- /dev/null +++ b/magnum_ui/static/dashboard/containers/containers.module.js @@ -0,0 +1,33 @@ +/** + * Copyright 2015 Cisco Systems, 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. + */ + +(function() { + 'use strict'; + + /** + * @ngdoc overview + * @name horizon.dashboard.containers + * + * @description + * Dashboard module to host various containers panels. + */ + angular + .module('horizon.dashboard.containers', [ + 'horizon.dashboard.containers.bay', + 'horizon.dashboard.containers.baymodel' + ]); + +})(); diff --git a/magnum_ui/static/dashboard/containers/containers.module.spec.js b/magnum_ui/static/dashboard/containers/containers.module.spec.js new file mode 100644 index 00000000..2ca5b369 --- /dev/null +++ b/magnum_ui/static/dashboard/containers/containers.module.spec.js @@ -0,0 +1,25 @@ +/** + * Copyright 2015 Cisco Systems, 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. + */ +(function() { + 'use strict'; + + describe('horizon.dashboard.containers', function() { + it('should exist', function() { + expect(angular.module('horizon.dashboard.containers')).toBeDefined(); + }); + }); + +})(); diff --git a/magnum_ui/static/dashboard/containers/containers.scss b/magnum_ui/static/dashboard/containers/containers.scss new file mode 100644 index 00000000..bb28c275 --- /dev/null +++ b/magnum_ui/static/dashboard/containers/containers.scss @@ -0,0 +1,9 @@ +// Custom Theme Variables +@import "/custom/variables"; +@import "/dashboard/scss/variables"; + +// Custom Style Variables +@import "/custom/styles"; + +@import "baymodel/baymodel"; +@import "bay/bay"; diff --git a/magnum_ui/test/__init__.py b/magnum_ui/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/magnum_ui/test/integration_tests/__init__.py b/magnum_ui/test/integration_tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/magnum_ui/version.py b/magnum_ui/version.py new file mode 100644 index 00000000..54b794db --- /dev/null +++ b/magnum_ui/version.py @@ -0,0 +1,3 @@ +import pbr.version + +version_info = pbr.version.VersionInfo('magnum-ui') diff --git a/manage.py b/manage.py new file mode 100755 index 00000000..f45a1fe6 --- /dev/null +++ b/manage.py @@ -0,0 +1,23 @@ +#!/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 # noqa + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", + "magnum_ui.test.settings") + execute_from_command_line(sys.argv) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..61fda81f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,39 @@ +# 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.0,>=1.6 +python-magnumclient>=0.2.1 +Babel>=1.3 +Django<1.9,>=1.7 +django-babel>=0.3.4 +django_compressor>=1.4 +django_openstack_auth>=1.4.0 +django-pyscss>=2.0.2 # BSD License (2 clause) +XStatic>=1.0.0 # MIT License +XStatic-Angular>=1.3.7 # MIT License +XStatic-Angular-Bootstrap>=0.11.0.2 # MIT License +XStatic-Angular-Gettext>=2.1.0.2 # MIT License +XStatic-Angular-lrdragndrop>=1.0.2.2 # MIT License +XStatic-Bootstrap-Datepicker>=1.3.1.0 # Apache 2.0 License +XStatic-Bootstrap-SCSS>=3 # Apache 2.0 License +XStatic-D3>=3.1.6.2 # BSD License (3 clause) +XStatic-Hogan>=2.0.0.2 # Apache 2.0 License +XStatic-Font-Awesome>=4.3.0 # SIL OFL 1.1 License, MIT License +XStatic-Jasmine>=2.1.2.0 # MIT License +XStatic-jQuery>=1.7.2 # MIT License +XStatic-JQuery-Migrate>=1.2.1.1 # MIT License +XStatic-JQuery.quicksearch>=2.0.3.1 # MIT License +XStatic-JQuery.TableSorter>=2.14.5.1 # MIT License +XStatic-jquery-ui>=1.10.1 # MIT License +XStatic-JSEncrypt>=2.0.0.2 # MIT License +XStatic-Magic-Search>=0.2.5.1 # Apache 2.0 License +XStatic-Rickshaw>=1.5.0 # BSD License (prior) +XStatic-smart-table>=1.4.5.3 # MIT License +XStatic-Spin>=1.2.5.2 # MIT License +XStatic-term.js>=0.0.4 # MIT License diff --git a/run_tests.sh b/run_tests.sh new file mode 100755 index 00000000..87913cc5 --- /dev/null +++ b/run_tests.sh @@ -0,0 +1,583 @@ +#!/bin/bash + +set -o errexit + +function usage { + echo "Usage: $0 [OPTION]..." + echo "Run Horizon's test suite(s)" + echo "" + echo " -V, --virtual-env Always use virtualenv. Install automatically" + echo " if not present" + echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local" + echo " environment" + echo " -c, --coverage Generate reports using Coverage" + echo " -f, --force Force a clean re-build of the virtual" + echo " environment. Useful when dependencies have" + echo " been added." + echo " -m, --manage Run a Django management command." + echo " --makemessages Create/Update English translation files." + echo " --compilemessages Compile all translation files." + echo " --check-only Do not update translation files (--makemessages only)." + echo " --pseudo Pseudo translate a language." + echo " -p, --pep8 Just run pep8" + echo " -8, --pep8-changed []" + echo " Just run PEP8 and HACKING compliance check" + echo " on files changed since HEAD~1 (or )" + echo " -P, --no-pep8 Don't run pep8 by default" + echo " -t, --tabs Check for tab characters in files." + echo " -y, --pylint Just run pylint" + echo " -e, --eslint Just run eslint" + echo " -k, --karma Just run karma" + echo " -q, --quiet Run non-interactively. (Relatively) quiet." + echo " Implies -V if -N is not set." + echo " --only-selenium Run only the Selenium unit tests" + echo " --with-selenium Run unit tests including Selenium tests" + echo " --selenium-headless Run Selenium tests headless" + echo " --integration Run the integration tests (requires a running " + echo " OpenStack environment)" + echo " --runserver Run the Django development server for" + echo " openstack_dashboard in the virtual" + echo " environment." + echo " --docs Just build the documentation" + echo " --backup-environment Make a backup of the environment on exit" + echo " --restore-environment Restore the environment before running" + echo " --destroy-environment Destroy the environment and exit" + echo " -h, --help Print this usage message" + echo "" + echo "Note: with no options specified, the script will try to run the tests in" + echo " a virtual environment, If no virtualenv is found, the script will ask" + echo " if you would like to create one. If you prefer to run tests NOT in a" + echo " virtual environment, simply pass the -N option." + exit +} + +# DEFAULTS FOR RUN_TESTS.SH +# +root=`pwd -P` +venv=$root/.venv +venv_env_version=$venv/environments +with_venv=tools/with_venv.sh +included_dirs="magnum_ui" + +always_venv=0 +backup_env=0 +command_wrapper="" +destroy=0 +force=0 +just_pep8=0 +just_pep8_changed=0 +no_pep8=0 +just_pylint=0 +just_docs=0 +just_tabs=0 +just_eslint=0 +just_karma=0 +never_venv=0 +quiet=0 +restore_env=0 +runserver=0 +only_selenium=0 +with_selenium=0 +selenium_headless=0 +integration=0 +testopts="" +testargs="" +with_coverage=0 +makemessages=0 +compilemessages=0 +check_only=0 +pseudo=0 +manage=0 + +# Jenkins sets a "JOB_NAME" variable, if it's not set, we'll make it "default" +[ "$JOB_NAME" ] || JOB_NAME="default" + +function process_option { + # If running manage command, treat the rest of options as arguments. + if [ $manage -eq 1 ]; then + testargs="$testargs $1" + return 0 + fi + + case "$1" in + -h|--help) usage;; + -V|--virtual-env) always_venv=1; never_venv=0;; + -N|--no-virtual-env) always_venv=0; never_venv=1;; + -p|--pep8) just_pep8=1;; + -8|--pep8-changed) just_pep8_changed=1;; + -P|--no-pep8) no_pep8=1;; + -y|--pylint) just_pylint=1;; + -e|--eslint) just_eslint=1;; + -k|--karma) just_karma=1;; + -f|--force) force=1;; + -t|--tabs) just_tabs=1;; + -q|--quiet) quiet=1;; + -c|--coverage) with_coverage=1;; + -m|--manage) manage=1;; + --makemessages) makemessages=1;; + --compilemessages) compilemessages=1;; + --check-only) check_only=1;; + --pseudo) pseudo=1;; + --only-selenium) only_selenium=1;; + --with-selenium) with_selenium=1;; + --selenium-headless) selenium_headless=1;; + --integration) integration=1;; + --docs) just_docs=1;; + --runserver) runserver=1;; + --backup-environment) backup_env=1;; + --restore-environment) restore_env=1;; + --destroy-environment) destroy=1;; + -*) testopts="$testopts $1";; + *) testargs="$testargs $1" + esac +} + +function run_management_command { + ${command_wrapper} python $root/manage.py $testopts $testargs +} + +function run_server { + echo "Starting Django development server..." + ${command_wrapper} python $root/manage.py runserver $testopts $testargs + echo "Server stopped." +} + +function run_pylint { + echo "Running pylint ..." + PYTHONPATH=$root ${command_wrapper} pylint --rcfile=.pylintrc -f parseable $included_dirs > pylint.txt || true + CODE=$? + grep Global -A2 pylint.txt + if [ $CODE -lt 32 ]; then + echo "Completed successfully." + exit 0 + else + echo "Completed with problems." + exit $CODE + fi +} + +function run_eslint { + echo "Running eslint ..." + if [ "`which npm`" == '' ] ; then + echo "npm is not present; please install, e.g. sudo apt-get install npm" + else + npm install + npm run lint + fi +} + +function run_karma { + echo "Running karma ..." + npm install + npm run test +} + +function warn_on_flake8_without_venv { + set +o errexit + ${command_wrapper} python -c "import hacking" 2>/dev/null + no_hacking=$? + set -o errexit + if [ $never_venv -eq 1 -a $no_hacking -eq 1 ]; then + echo "**WARNING**:" >&2 + echo "OpenStack hacking is not installed on your host. Its detection will be missed." >&2 + echo "Please install or use virtual env if you need OpenStack hacking detection." >&2 + fi +} + +function run_pep8 { + echo "Running flake8 ..." + warn_on_flake8_without_venv + DJANGO_SETTINGS_MODULE=magnum_ui.test.settings ${command_wrapper} flake8 +} + +function run_pep8_changed { + # NOTE(gilliard) We want use flake8 to check the entirety of every file that has + # a change in it. Unfortunately the --filenames argument to flake8 only accepts + # file *names* and there are no files named (eg) "nova/compute/manager.py". The + # --diff argument behaves surprisingly as well, because although you feed it a + # diff, it actually checks the file on disk anyway. + local base_commit=${testargs:-HEAD~1} + files=$(git diff --name-only $base_commit | tr '\n' ' ') + echo "Running flake8 on ${files}" + warn_on_flake8_without_venv + diff -u --from-file /dev/null ${files} | DJANGO_SETTINGS_MODULE=magnum_ui.test.settings ${command_wrapper} flake8 --diff + exit +} + +function run_sphinx { + echo "Building sphinx..." + DJANGO_SETTINGS_MODULE=magnum_ui.test.settings ${command_wrapper} python setup.py build_sphinx + echo "Build complete." +} + +function tab_check { + TAB_VIOLATIONS=`find $included_dirs -type f -regex ".*\.\(css\|js\|py\|html\)" -print0 | xargs -0 awk '/\t/' | wc -l` + if [ $TAB_VIOLATIONS -gt 0 ]; then + echo "TABS! $TAB_VIOLATIONS of them! Oh no!" + HORIZON_FILES=`find $included_dirs -type f -regex ".*\.\(css\|js\|py|\html\)"` + for TABBED_FILE in $HORIZON_FILES + do + TAB_COUNT=`awk '/\t/' $TABBED_FILE | wc -l` + if [ $TAB_COUNT -gt 0 ]; then + echo "$TABBED_FILE: $TAB_COUNT" + fi + done + fi + return $TAB_VIOLATIONS; +} + +function destroy_venv { + echo "Cleaning environment..." + echo "Removing virtualenv..." + rm -rf $venv + echo "Virtualenv removed." +} + +function environment_check { + echo "Checking environment." + if [ -f $venv_env_version ]; then + set +o errexit + cat requirements.txt test-requirements.txt | cmp $venv_env_version - > /dev/null + local env_check_result=$? + set -o errexit + if [ $env_check_result -eq 0 ]; then + # If the environment exists and is up-to-date then set our variables + command_wrapper="${root}/${with_venv}" + echo "Environment is up to date." + return 0 + fi + fi + + if [ $always_venv -eq 1 ]; then + install_venv + else + if [ ! -e ${venv} ]; then + echo -e "Environment not found. Install? (Y/n) \c" + else + echo -e "Your environment appears to be out of date. Update? (Y/n) \c" + fi + read update_env + if [ "x$update_env" = "xY" -o "x$update_env" = "x" -o "x$update_env" = "xy" ]; then + install_venv + else + # Set our command wrapper anyway. + command_wrapper="${root}/${with_venv}" + fi + fi +} + +function sanity_check { + # Anything that should be determined prior to running the tests, server, etc. + # Don't sanity-check anything environment-related in -N flag is set + if [ $never_venv -eq 0 ]; then + if [ ! -e ${venv} ]; then + echo "Virtualenv not found at $venv. Did install_venv.py succeed?" + exit 1 + fi + fi + # Remove .pyc files. This is sanity checking because they can linger + # after old files are deleted. + find . -name "*.pyc" -exec rm -rf {} \; +} + +function backup_environment { + if [ $backup_env -eq 1 ]; then + echo "Backing up environment \"$JOB_NAME\"..." + if [ ! -e ${venv} ]; then + echo "Environment not installed. Cannot back up." + return 0 + fi + if [ -d /tmp/.horizon_environment/$JOB_NAME ]; then + mv /tmp/.horizon_environment/$JOB_NAME /tmp/.horizon_environment/$JOB_NAME.old + rm -rf /tmp/.horizon_environment/$JOB_NAME + fi + mkdir -p /tmp/.horizon_environment/$JOB_NAME + cp -r $venv /tmp/.horizon_environment/$JOB_NAME/ + # Remove the backup now that we've completed successfully + rm -rf /tmp/.horizon_environment/$JOB_NAME.old + echo "Backup completed" + fi +} + +function restore_environment { + if [ $restore_env -eq 1 ]; then + echo "Restoring environment from backup..." + if [ ! -d /tmp/.horizon_environment/$JOB_NAME ]; then + echo "No backup to restore from." + return 0 + fi + + cp -r /tmp/.horizon_environment/$JOB_NAME/.venv ./ || true + echo "Environment restored successfully." + fi +} + +function install_venv { + # Install with install_venv.py + export PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE-/tmp/.pip_download_cache} + export PIP_USE_MIRRORS=true + if [ $quiet -eq 1 ]; then + export PIP_NO_INPUT=true + fi + echo "Fetching new src packages..." + rm -rf $venv/src + python tools/install_venv.py + command_wrapper="$root/${with_venv}" + # Make sure it worked and record the environment version + sanity_check + chmod -R 754 $venv + cat requirements.txt test-requirements.txt > $venv_env_version +} + +function run_tests { + sanity_check + + if [ $with_selenium -eq 1 ]; then + export WITH_SELENIUM=1 + elif [ $only_selenium -eq 1 ]; then + export WITH_SELENIUM=1 + export SKIP_UNITTESTS=1 + fi + + if [ $with_selenium -eq 0 -a $integration -eq 0 ]; then + testopts="$testopts --exclude-dir=magnum_ui/test/integration_tests" + fi + + if [ $selenium_headless -eq 1 ]; then + export SELENIUM_HEADLESS=1 + fi + + if [ -z "$testargs" ]; then + run_tests_all + else + run_tests_subset + fi +} + +function run_tests_subset { + project=`echo $testargs | awk -F. '{print $1}'` + ${command_wrapper} python $root/manage.py test --settings=$project.test.settings $testopts $testargs +} + +function run_tests_all { + echo "Running Magnum UI tests" + export NOSE_XUNIT_FILE=magnum_ui/nosetests.xml + if [ "$NOSE_WITH_HTML_OUTPUT" = '1' ]; then + export NOSE_HTML_OUT_FILE='dashboard_nose_results.html' + fi + ${command_wrapper} ${coverage_run} $root/manage.py test magnum_ui --settings=openstack_dashboard.test.settings $testopts + # get results of the openstack_dashboard tests + DASHBOARD_RESULT=$? + + if [ $with_coverage -eq 1 ]; then + echo "Generating coverage reports" + ${command_wrapper} python -m coverage.__main__ combine + ${command_wrapper} python -m coverage.__main__ xml -i --include="horizon/*,openstack_dashboard/*" --omit='/usr*,setup.py,*egg*,.venv/*' + ${command_wrapper} python -m coverage.__main__ html -i --include="horizon/*,openstack_dashboard/*" --omit='/usr*,setup.py,*egg*,.venv/*' -d reports + fi + # Remove the leftover coverage files from the -p flag earlier. + rm -f .coverage.* + + PEP8_RESULT=0 + if [ $no_pep8 -eq 0 ] && [ $only_selenium -eq 0 ]; then + run_pep8 + PEP8_RESULT=$? + fi + + TEST_RESULT=$(($DASHBOARD_RESULT || $PEP8_RESULT)) + if [ $TEST_RESULT -eq 0 ]; then + echo "Tests completed successfully." + else + echo "Tests failed." + fi + exit $TEST_RESULT +} + +function run_integration_tests { + export INTEGRATION_TESTS=1 + + if [ $selenium_headless -eq 1 ]; then + export SELENIUM_HEADLESS=1 + fi + + echo "Running Horizon integration tests..." + if [ -z "$testargs" ]; then + ${command_wrapper} nosetests openstack_dashboard/test/integration_tests/tests + else + ${command_wrapper} nosetests $testargs + fi + exit 0 +} + +function babel_extract { + DOMAIN=$1 + KEYWORDS="-k gettext_noop -k gettext_lazy -k ngettext_lazy:1,2" + KEYWORDS+=" -k ugettext_noop -k ugettext_lazy -k ungettext_lazy:1,2" + KEYWORDS+=" -k npgettext:1c,2,3 -k pgettext_lazy:1c,2 -k npgettext_lazy:1c,2,3" + + ${command_wrapper} pybabel extract -F babel-${DOMAIN}.cfg -o locale/${DOMAIN}.pot $KEYWORDS . +} + +function run_makemessages { + + echo -n "magnum ui: " + cd magnum_ui + babel_extract django + MAGNUM_PY_RESULT=$? + + echo -n "magnum ui javascript: " + babel_extract djangojs + MAGNUM_JS_RESULT=$? + + cd .. + if [ $check_only -eq 1 ]; then + git checkout -- magnum_ui/locale/django*.pot + fi + + exit $(($MAGNUM_PY_RESULT || $MAGNUM_JS_RESULT)) +} + +function run_compilemessages { + cd horizon + ${command_wrapper} $root/manage.py compilemessages + HORIZON_PY_RESULT=$? + cd ../openstack_dashboard + ${command_wrapper} $root/manage.py compilemessages + DASHBOARD_RESULT=$? + exit $(($HORIZON_PY_RESULT || $DASHBOARD_RESULT)) +} + +function run_pseudo { + for lang in $testargs + # Use English pot file as the source file/pot file just like real Horizon translations + do + ${command_wrapper} $root/tools/pseudo.py openstack_dashboard/locale/django.pot openstack_dashboard/locale/$lang/LC_MESSAGES/django.po $lang + ${command_wrapper} $root/tools/pseudo.py openstack_dashboard/locale/djangojs.pot openstack_dashboard/locale/$lang/LC_MESSAGES/djangojs.po $lang + ${command_wrapper} $root/tools/pseudo.py horizon/locale/django.pot horizon/locale/$lang/LC_MESSAGES/django.po $lang + ${command_wrapper} $root/tools/pseudo.py horizon/locale/djangojs.pot horizon/locale/$lang/LC_MESSAGES/djangojs.po $lang + done + exit $? +} + + +# ---------PREPARE THE ENVIRONMENT------------ # + +# PROCESS ARGUMENTS, OVERRIDE DEFAULTS +for arg in "$@"; do + process_option $arg +done + +if [ $quiet -eq 1 ] && [ $never_venv -eq 0 ] && [ $always_venv -eq 0 ] +then + always_venv=1 +fi + +# If destroy is set, just blow it away and exit. +if [ $destroy -eq 1 ]; then + destroy_venv + exit 0 +fi + +# Ignore all of this if the -N flag was set +if [ $never_venv -eq 0 ]; then + + # Restore previous environment if desired + if [ $restore_env -eq 1 ]; then + restore_environment + fi + + # Remove the virtual environment if --force used + if [ $force -eq 1 ]; then + destroy_venv + fi + + # Then check if it's up-to-date + environment_check + + # Create a backup of the up-to-date environment if desired + if [ $backup_env -eq 1 ]; then + backup_environment + fi +fi + +# ---------EXERCISE THE CODE------------ # + +# Run management commands +if [ $manage -eq 1 ]; then + run_management_command + exit $? +fi + +# Build the docs +if [ $just_docs -eq 1 ]; then + run_sphinx + exit $? +fi + +# Update translation files +if [ $makemessages -eq 1 ]; then + run_makemessages + exit $? +fi + +# Compile translation files +if [ $compilemessages -eq 1 ]; then + run_compilemessages + exit $? +fi + +# Generate Pseudo translation +if [ $pseudo -eq 1 ]; then + run_pseudo + exit $? +fi + +# PEP8 +if [ $just_pep8 -eq 1 ]; then + run_pep8 + exit $? +fi + +if [ $just_pep8_changed -eq 1 ]; then + run_pep8_changed + exit $? +fi + +# Pylint +if [ $just_pylint -eq 1 ]; then + run_pylint + exit $? +fi + +# ESLint +if [ $just_eslint -eq 1 ]; then + run_eslint + exit $? +fi + +# Karma +if [ $just_karma -eq 1 ]; then + run_karma + exit $? +fi + +# Tab checker +if [ $just_tabs -eq 1 ]; then + tab_check + exit $? +fi + +# Integration tests +if [ $integration -eq 1 ]; then + run_integration_tests + exit $? +fi + +# Django development server +if [ $runserver -eq 1 ]; then + run_server + exit $? +fi + +# Full test suite +run_tests || exit diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..863a8a0b --- /dev/null +++ b/setup.cfg @@ -0,0 +1,26 @@ +[metadata] +name = magnum-ui +version = 0.0.1 +summary = Magnum User Interface +description-file = + README.rst +author = OpenStack +author-email = openstack-dev@lists.openstack.org +home-page = http://www.openstack.org/ +classifier = + Environment :: OpenStack + Intended Audience :: Information Technology + Intended Audience :: System Administrators + License :: OSI Approved :: Apache Software License + Operating System :: POSIX :: Linux + Programming Language :: Python + Programming Language :: Python :: 2 + Programming Language :: Python :: 2.7 + Programming Language :: Python :: 2.6 + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.3 + Programming Language :: Python :: 3.4 + +[files] +packages = + magnum diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..73637574 --- /dev/null +++ b/setup.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT +import setuptools + +# In python < 2.7.4, a lazy loading of package `pbr` will break +# setuptools if some other modules registered functions in `atexit`. +# solution from: http://bugs.python.org/issue15881#msg170215 +try: + import multiprocessing # noqa +except ImportError: + pass + +setuptools.setup( + setup_requires=['pbr'], + pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 00000000..ee491a13 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,29 @@ +# 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<0.11,>=0.10.2 +# +coverage>=3.6 +django-nose>=1.2 +mock>=1.2 +mox3>=0.7.0 +nodeenv>=0.9.4 # BSD License +nose +nose-exclude +nosehtmloutput>=0.0.3 +nosexcover +openstack.nose-plugin>=0.7 +oslosphinx>=2.5.0 # Apache-2.0 +selenium +sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 +testtools>=1.4.0 +# This also needs xvfb library installed on your OS +xvfbwrapper>=0.1.3 #license: MIT +# Include horizon as test requirement +http://tarballs.openstack.org/horizon/horizon-master.tar.gz#egg=horizon diff --git a/tools/install_venv.py b/tools/install_venv.py new file mode 100644 index 00000000..e96521ea --- /dev/null +++ b/tools/install_venv.py @@ -0,0 +1,71 @@ +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# Copyright 2010 OpenStack Foundation +# Copyright 2013 IBM Corp. +# +# 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 + +import install_venv_common as install_venv # noqa + + +def print_help(venv, root): + help = """ + OpenStack development environment setup is complete. + + OpenStack development uses virtualenv to track and manage Python + dependencies while in development and testing. + + To activate the OpenStack virtualenv for the extent of your current shell + session you can run: + + $ source %s/bin/activate + + Or, if you prefer, you can run commands in the virtualenv on a case by case + basis by running: + + $ %s/tools/with_venv.sh + + Also, make test will automatically use the virtualenv. + """ + print(help % (venv, root)) + + +def main(argv): + root = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + + if os.environ.get('tools_path'): + root = os.environ['tools_path'] + venv = os.path.join(root, '.venv') + if os.environ.get('venv'): + venv = os.environ['venv'] + + pip_requires = os.path.join(root, 'requirements.txt') + test_requires = os.path.join(root, 'test-requirements.txt') + py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1]) + project = 'OpenStack' + install = install_venv.InstallVenv(root, venv, pip_requires, test_requires, + py_version, project) + options = install.parse_args(argv) + install.check_python_version() + install.check_dependencies() + install.create_virtualenv(no_site_packages=options.no_site_packages) + install.install_dependencies() + print_help(venv, root) + +if __name__ == '__main__': + main(sys.argv) diff --git a/tools/with_venv.sh b/tools/with_venv.sh new file mode 100755 index 00000000..7303990b --- /dev/null +++ b/tools/with_venv.sh @@ -0,0 +1,7 @@ +#!/bin/bash +TOOLS_PATH=${TOOLS_PATH:-$(dirname $0)} +VENV_PATH=${VENV_PATH:-${TOOLS_PATH}} +VENV_DIR=${VENV_NAME:-/../.venv} +TOOLS=${TOOLS_PATH} +VENV=${VENV:-${VENV_PATH}/${VENV_DIR}} +source ${VENV}/bin/activate && "$@" diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..7234faf8 --- /dev/null +++ b/tox.ini @@ -0,0 +1,87 @@ +[tox] +envlist = py27,py27dj17,py27dj18,pep834 +minversion = 1.6 +skipsdist = True + +[testenv] +usedevelop = True +install_command = pip install -U {opts} {packages} +setenv = VIRTUAL_ENV={envdir} + NOSE_WITH_OPENSTACK=1 + NOSE_OPENSTACK_COLOR=1 + NOSE_OPENSTACK_RED=0.05 + NOSE_OPENSTACK_YELLOW=0.025 + NOSE_OPENSTACK_SHOW_ELAPSED=1 +# Note the hash seed is set to 0 until horizon can be tested with a +# random hash seed successfully. + PYTHONHASHSEED=0 +deps = -r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt +commands = /bin/bash run_tests.sh -N --no-pep8 {posargs} + +[testenv:pep8] +commands = + /bin/bash run_tests.sh -N --pep8 + /bin/bash run_tests.sh -N --makemessages --check-only + +[testenv:venv] +commands = {posargs} + +[testenv:cover] +commands = /bin/bash run_tests.sh -N --no-pep8 --coverage {posargs} + +[testenv:py27dj17] +basepython = python2.7 +commands = pip install django>=1.7,<1.8 + /bin/bash run_tests.sh -N --no-pep8 {posargs} + +[testenv:py27dj18] +basepython = python2.7 +commands = pip install django>=1.8,<1.9 + /bin/bash run_tests.sh -N --no-pep8 {posargs} + +[testenv:py27integration] +basepython = python2.7 +commands = /bin/bash run_tests.sh -N --integration --selenium-headless {posargs} + +[testenv:eslint] +passenv = * +commands = nodeenv -p + npm install + /bin/bash run_tests.sh -N --eslint + +[testenv:docs] +setenv = DJANGO_SETTINGS_MODULE=openstack_dashboard.test.settings +commands = python setup.py build_sphinx + +[tox:jenkins] +downloadcache = ~/cache/pip + +[flake8] +exclude = .venv,.git,.tox,dist,*openstack/common*,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py,*/local/*,*/test/test_plugins/*,.ropeproject +# H405 multi line docstring summary not separated with an empty line +ignore = H405 +max-complexity = 20 + +[hacking] +import_exceptions = collections.defaultdict, + django.conf.settings, + django.conf.urls.include, + django.conf.urls.patterns, + django.conf.urls.url, + django.core.urlresolvers.reverse, + django.core.urlresolvers.reverse_lazy, + django.template.loader.render_to_string, + django.test.utils.override_settings, + django.utils.datastructures.SortedDict, + django.utils.encoding.force_text, + django.utils.html.conditional_escape, + django.utils.html.escape, + django.utils.http.urlencode, + django.utils.safestring.mark_safe, + django.utils.translation.npgettext_lazy, + django.utils.translation.pgettext_lazy, + django.utils.translation.ugettext_lazy, + django.utils.translation.ungettext_lazy, + operator.attrgetter, + StringIO.StringIO