diff options
Diffstat (limited to 'docs/source')
-rw-r--r-- | docs/source/_static/.gitignore | 0 | ||||
-rw-r--r-- | docs/source/conf.py | 391 | ||||
-rw-r--r-- | docs/source/faq.rst | 37 | ||||
-rw-r--r-- | docs/source/glossary.rst | 19 | ||||
-rw-r--r-- | docs/source/index.rst | 101 | ||||
-rw-r--r-- | docs/source/intro.rst | 124 | ||||
-rw-r--r-- | docs/source/quickstart.rst | 146 | ||||
-rw-r--r-- | docs/source/ref/context_processors.rst | 6 | ||||
-rw-r--r-- | docs/source/ref/decorators.rst | 6 | ||||
-rw-r--r-- | docs/source/ref/exceptions.rst | 6 | ||||
-rw-r--r-- | docs/source/ref/forms.rst | 17 | ||||
-rw-r--r-- | docs/source/ref/horizon.rst | 42 | ||||
-rw-r--r-- | docs/source/ref/middleware.rst | 6 | ||||
-rw-r--r-- | docs/source/ref/run_tests.rst | 100 | ||||
-rw-r--r-- | docs/source/ref/users.rst | 6 | ||||
-rw-r--r-- | docs/source/ref/views.rst | 12 | ||||
-rw-r--r-- | docs/source/testing.rst | 62 |
17 files changed, 1081 insertions, 0 deletions
diff --git a/docs/source/_static/.gitignore b/docs/source/_static/.gitignore new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/docs/source/_static/.gitignore diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..a1f7a3a8 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,391 @@ +# -*- coding: utf-8 -*- +# +# 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. + +import sys, os +import horizon.version + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +HORIZON_DIR = os.path.abspath(os.path.join(BASE_DIR, "..", "..", "horizon")) +DASHBOARD_DIR = os.path.abspath(os.path.join(BASE_DIR, "..", "..", "openstack-dashboard")) + +sys.path.insert(0, HORIZON_DIR) +sys.path.insert(0, DASHBOARD_DIR) + +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.endswith(".py"): + # root = ./dashboard/test/unit + # filename = base.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 = {'horizon': HORIZON_DIR, + 'dashboard': DASHBOARD_DIR} + + if not(os.path.exists(RSTDIR)): + os.mkdir(RSTDIR) + + INDEXOUT = open(os.path.join(RSTDIR, "autoindex.rst"), "w") + INDEXOUT.write("=================\n") + INDEXOUT.write("Source Code Index\n") + INDEXOUT.write("=================\n") + + for modulename, path in SRCS.items(): + 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") + if not(os.path.exists(os.path.join(RSTDIR, modulename))): + os.mkdir(os.path.join(RSTDIR, modulename)) + for module in find_autodoc_modules(modulename, path): + mod_path = os.path.join(path, *module.split(".")) + generated_file = os.path.join(RSTDIR, modulename, "%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")) + + # 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() + +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.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.pngmath', + 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +if os.getenv('HUDSON_PUBLISH_DOCS'): + templates_path = ['_ga', '_templates'] +else: + 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'Horizon' +copyright = u'2011, OpenStack, LLC' + +# 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 = horizon.version.canonical_version_string() +# The full version, including alpha/beta/rc tags. +release = horizon.version.canonical_version_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 = 'default' + +# 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 +# "<project> v<release> 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' + +# 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 <link> 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, LLC', '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', 'horizon', u'Horizon Documentation', + [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'2011, 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 a 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 + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'python': ('http://docs.python.org/', None), + 'django': ('http://docs.djangoproject.com/en/dev/_objects/'), + 'nova': ('http://nova.openstack.org', None), + 'swift': ('http://swift.openstack.org', None), + 'keystone': ('http://keystone.openstack.org', None), + 'glance': ('http://glance.openstack.org', None)} diff --git a/docs/source/faq.rst b/docs/source/faq.rst new file mode 100644 index 00000000..26836ef6 --- /dev/null +++ b/docs/source/faq.rst @@ -0,0 +1,37 @@ +========================== +Frequently Asked Questions +========================== + +What is the relationship between ``Dashboards``, ``Panels``, and navigation? + + The navigational structure is strongly encouraged to flow from + ``Dashboard`` objects as top-level navigation items to ``Panel`` objects as + sub-navigation items as in the current implementation. Template tags + are provided to automatically generate this structure. + + That said, you are not required to use the provided tools and can write + templates and URLconfs by hand to create any desired structure. + +Does a panel have to be an app in ``INSTALLED_APPS``? + + A panel can live in any Python module. It can be a standalone which ties + into an existing dashboard, or it can be contained alongside others within + a larger dashboard "app". There is no strict enforcement here. Python + is "a language for consenting adults." A module containing a Panel does + not need to be added to ``INSTALLED_APPS``, but this is a common and + convenient way to load a standalone panel. + +Could I hook an external service into a panel using, for example, an iFrame? + + Panels are just entry-points to hook views into the larger dashboard + navigational structure and enforce common attributes like RBAC. The + view and corresponding templates can contain anything you would like, + including iFrames. + +What does this mean for visual design? + + The ability to add an arbitrary number of top-level navigational items + (``Dashboard`` objects) poses a new design challenge. Horizon's lead + designer has taken on the challenge of providing a reference design + for Horizon which supports this possibility. + diff --git a/docs/source/glossary.rst b/docs/source/glossary.rst new file mode 100644 index 00000000..cca87400 --- /dev/null +++ b/docs/source/glossary.rst @@ -0,0 +1,19 @@ +======== +Glossary +======== + +Horizon + + The OpenStack dashboard project. Also the name of the top-level + Python object which handles registration for the app. + +Dashboard + + A Python class representing a top-level navigation item (e.g. "syspanel") + which provides a consistent API for Horizon-compatible applications. + +Panel + + A Python class representing a sub-navigation item (e.g. "instances") + which contains all the necessary logic (views, forms, tests, etc.) for + that interface. diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..c326d6de --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,101 @@ +.. + Copyright 2011 OpenStack, LLC + 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. + +======================================== +Horizon: The OpenStack Dashboard Project +======================================== + +Introduction +============ + +Horizon is the canonical implementation of `Openstack's Dashboard +<https://github.com/openstack/horizon>`_, which provides a web based user +interface to OpenStack services including Nova, Swift, Keystone, etc. + +For a more in-depth look at Horizon and it's architecture, see the +:doc:`Introduction to Horizon <intro>`. + +To learn what you need to know to get going, see the :doc:`quickstart`. + +Getting Started With Horizon +============================ + +How to use Horizon in your own projects. + +.. toctree:: + :maxdepth: 1 + + intro + quickstart + + +Developer Reference +=================== + +For those wishing to develop Horizon itself, or go in-depth with building +your own :class:`~horizon.Dashboard` or :class:`~horizon.Panel` classes, +the following documentation is provided. + +Topics +------ + +Brief guides to areas of interest and importance when developing Horizon. + +.. toctree:: + :maxdepth: 1 + + testing + +API Reference +------------- + +In-depth documentation for Horizon and it's APIs. + +.. toctree:: + :maxdepth: 1 + + ref/run_tests + ref/horizon + ref/users + ref/forms + ref/views + ref/middleware + ref/context_processors + ref/decorators + ref/exceptions + +Source Code Reference +--------------------- + +Auto-generated reference for the complete source code. + +.. toctree:: + :maxdepth: 1 + + sourcecode/autoindex + + +Information +=========== + +.. toctree:: + :maxdepth: 1 + + faq + glossary + +* :ref:`genindex` +* :ref:`modindex` diff --git a/docs/source/intro.rst b/docs/source/intro.rst new file mode 100644 index 00000000..83f7819f --- /dev/null +++ b/docs/source/intro.rst @@ -0,0 +1,124 @@ +=================== +Introducing Horizon +=================== + +.. contents:: Contents: + :local: + +Values +====== + + "Think simple" as my old master used to say - meaning reduce + the whole of its parts into the simplest terms, getting back + to first principles. + + -- Frank Lloyd Wright + +Horizon holds several key values at the core of it's design and architecture: + + * Core Support: Out-of-the-box support for all core OpenStack projects. + * Extensible: Anyone can add a new component as a "first-class citizen". + * Manageable: The core codebase should be simple and easy-to-navigate. + * Consistent: Visual and interaction paradigms are maintained throughout. + * Stable: A reliable API with an emphasis on backwards-compatibility. + * Usable: Providing an *awesome* interface that people *want* to use. + +The only way to attain and uphold those ideals is to make it *easy* for +developers to implement those values. + +History +======= + +Horizon started life as a single app to manage OpenStack's compute project. +As such, all it needed was a set of views, templates, and API calls. + +From there it grew to support multiple OpenStack projects and APIs gradually, +arranged rigidly into "dash" and "syspanel" groupings. + +During the "Diablo" release cycle an initial plugin system was added using +signals to hook in additional URL patterns and add links into the "dash" +and "syspanel" navigation. + +This incremental growth served the goal of "Core Support" phenomenally, but +left "Extensible" and "Manageable" behind. And while the other key values took +shape of their own accord, it was time to re-architect for an extensible, +modular future. + + +The Current Architecture & How It Meets Our Values +================================================== + +At it's core, **Horizon should be a registration pattern for +applications to hook into**. Here's what that means and how it's +implemented in terms of our values: + +Core Support +------------ + +Horizon ships with three central dashboards, a "User Dashboard", a +"System Dashboard", and a "Settings" dashboard. Between these three they +cover the core OpenStack applications and deliver on Core Support. + +The Horizon application also ships with a set of API abstractions +for the core OpenStack projects in order to provide a consistent, stable set +of reusable methods for developers. Using these abstractions, developers +working on Horizon don't need to be intimately familiar with the APIs of +each OpenStack project. + +Extensible +---------- + +A Horizon dashboard application is based around the :class:`~horizon.Dashboard` +class that provides a consistent API and set of capabilities for both +core OpenStack dashboard apps shipped with Horizon and equally for third-party +apps. The :class:`~horizon.Dashboard` class is treated as a top-level +navigation item. + +Should a developer wish to provide functionality within an existing dashboard +(e.g. adding a monitoring panel to the user dashboard) the simple registration +pattern makes it possible to write an app which hooks into other dashboards +just as easily as creating a new dashboard. All you have to do is import the +dashboard you wish to modify. + +Manageable +---------- + +Within the application, there is a simple method for registering a +:class:`~horizon.Panel` (sub-navigation items). Each panel contains the +necessary logic (views, forms, tests, etc.) for that interface. This granular +breakdown prevents files (such as ``api.py``) from becoming thousands of +lines long and makes code easy to find by correlating it directly to the +navigation. + +Consistent +---------- + +By providing the necessary core classes to build from, as well as a +solid set of reusable templates and additional tools (base form classes, +base widget classes, template tags, and perhaps even class-based views) +we can maintain consistency across applications. + +Stable +------ + +By architecting around these core classes and reusable components we +create an implicit contract that changes to these components will be +made in the most backwards-compatible ways whenever possible. + +Usable +------ + +Ultimately that's up to each and every developer that touches the code, +but if we get all the other goals out of the way then we are free to focus +on the best possible experience. + +.. seealso:: + + :doc:`Quickstart <quickstart>` + A short guide to getting started with using Horizon. + + :doc:`Frequently Asked Questions <faq>` + Common questions and answers. + + :doc:`Glossary <glossary>` + Common terms and their definitions. diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst new file mode 100644 index 00000000..2e010be9 --- /dev/null +++ b/docs/source/quickstart.rst @@ -0,0 +1,146 @@ +================== +Horizon Quickstart +================== + +Horizon's Structure +=================== + +This project is a bit different from other Openstack projects in that it is +composed of two distinct components: + + * ``horizon`` + * ``openstack-dashboard`` + +The ``horizon`` directory holds the generic libraries and components that can +be used in any Django project. In testing, this component is set up with +buildout (see :doc:`ref/run_tests`), and any dependencies that need to +be added to the ``horizon/buildout.cfg`` file. + +The ``openstack-dashboard`` directory contains a reference Django project that +uses ``horizon`` and is built with a virtualenv. If dependencies are added that +``openstack-dashboard`` requires they should be added to ``openstack- +dashboard/tools/pip-requires``. + +Project +======= + +INSTALLED_APPS +-------------- + +At the project level you add Horizon and any desired dashboards to your +``settings.INSTALLED_APPS``:: + + INSTALLED_APPS = ( + 'django', + ... + 'horizon', + 'horizon.dash', + 'horizon.syspanel', + ) + +URLs +---- + +Then you add a single line to your project's ``urls.py``:: + + url(r'', include(horizon.urls)), + +Those urls are automatically constructed based on the registered Horizon apps. +If a different URL structure is desired it can be constructed by hand. + +Templates +--------- + +Pre-built template tags generate navigation. In your ``nav.html`` +template you might have the following:: + + {% load horizon %} + + <div class='nav'> + {% horizon_main_nav %} + </div> + +And in your ``sidebar.html`` you might have:: + + {% load horizon %} + + <div class='sidebar'> + {% horizon_dashboard_nav %} + </div> + +These template tags are aware of the current "active" dashboard and panel +via template context variables and will render accordingly. + +Application +=========== + +Structure +--------- + +An application would have the following structure (we'll use syspanel as +an example):: + + syspanel/ + |---__init__.py + |---dashboard.py <-----Registers the app with Horizon and sets dashboard properties + |---templates/ + |---templatetags/ + |---overview/ + |---services/ + |---images/ + |---__init__.py + |---panel.py <-----Registers the panel in the app and defines panel properties + |---urls.py + |---views.py + |---forms.py + |---tests.py + |---api.py <-------Optional additional API methods for non-core services + |---templates/ + ... + ... + +Dashboard Classes +----------------- + +Inside of ``dashboard.py`` you would have a class definition and the registration +process:: + + import horizon + + + class Syspanel(horizon.Dashboard): + name = "Syspanel" # Appears in navigation + slug = 'syspanel' # Appears in url + panels = ('overview', 'services', 'instances', 'flavors', 'images', + 'tenants', 'users', 'quotas',) + default_panel = 'overview' + roles = ('admin',) # Provides RBAC at the dashboard-level + ... + + + horizon.register(Syspanel) + +Panel Classes +------------- + +To connect a :class:`~horizon.Panel` with a :class:`~horizon.Dashboard` class +you register it in a ``panels.py`` file like so:: + + import horizon + + from horizon.dashboard.syspanel import dashboard + + + class Images(horizon.Panel): + name = "Images" + slug = 'images' + roles = ('admin', 'my_other_role',) # Fine-grained RBAC per-panel + + + # You could also register your panel with another application's dashboard + dashboard.Syspanel.register(Images) + +By default a :class:`~horizon.Panel` class looks for a ``urls.py`` file in the +same directory as ``panel.py`` to include in the rollup of url patterns from +panels to dashboards to Horizon, resulting in a wholly extensible, configurable +URL structure. diff --git a/docs/source/ref/context_processors.rst b/docs/source/ref/context_processors.rst new file mode 100644 index 00000000..b34c0109 --- /dev/null +++ b/docs/source/ref/context_processors.rst @@ -0,0 +1,6 @@ +========================== +Horizon Context Processors +========================== + +.. automodule:: horizon.context_processors + :members: diff --git a/docs/source/ref/decorators.rst b/docs/source/ref/decorators.rst new file mode 100644 index 00000000..777afbe5 --- /dev/null +++ b/docs/source/ref/decorators.rst @@ -0,0 +1,6 @@ +================== +Horizon Decorators +================== + +.. automodule:: horizon.decorators + :members: diff --git a/docs/source/ref/exceptions.rst b/docs/source/ref/exceptions.rst new file mode 100644 index 00000000..4151f18f --- /dev/null +++ b/docs/source/ref/exceptions.rst @@ -0,0 +1,6 @@ +================== +Horizon Exceptions +================== + +.. automodule:: horizon.exceptions + :members: diff --git a/docs/source/ref/forms.rst b/docs/source/ref/forms.rst new file mode 100644 index 00000000..9b30cb8e --- /dev/null +++ b/docs/source/ref/forms.rst @@ -0,0 +1,17 @@ +============= +Horizon Forms +============= + +Horizon ships with a number of form classes, some generic and some specific. + +Generic Forms +============= + +.. automodule:: horizon.forms + :members: + +Auth Forms +========== + +.. automodule:: horizon.views.auth_forms + :members: diff --git a/docs/source/ref/horizon.rst b/docs/source/ref/horizon.rst new file mode 100644 index 00000000..9206e950 --- /dev/null +++ b/docs/source/ref/horizon.rst @@ -0,0 +1,42 @@ +====================== +The ``horizon`` Module +====================== + +.. module:: horizon + +Horizon ships with a single point of contact for hooking into your project if +you aren't developing your own :class:`~horizon.Dashboard` or +:class:`~horizon.Panel`:: + + import horizon + +From there you can access all the key methods you need. + +Horizon +======= + +.. attribute:: urls + + The auto-generated URLconf for Horizon. Usage:: + + url(r'', include(horizon.urls)), + +.. autofunction:: register +.. autofunction:: unregister +.. autofunction:: get_absolute_url +.. autofunction:: get_user_home +.. autofunction:: get_dashboard +.. autofunction:: get_default_dashboard +.. autofunction:: get_dashboards + +Dashboard +========= + +.. autoclass:: Dashboard + :members: + +Panel +===== + +.. autoclass:: Panel + :members: diff --git a/docs/source/ref/middleware.rst b/docs/source/ref/middleware.rst new file mode 100644 index 00000000..fcca5ff0 --- /dev/null +++ b/docs/source/ref/middleware.rst @@ -0,0 +1,6 @@ +================== +Horizon Middleware +================== + +.. automodule:: horizon.middleware + :members: diff --git a/docs/source/ref/run_tests.rst b/docs/source/ref/run_tests.rst new file mode 100644 index 00000000..201198ed --- /dev/null +++ b/docs/source/ref/run_tests.rst @@ -0,0 +1,100 @@ +=========================== +The ``run_tests.sh`` Script +=========================== + +Horizon ships with a script called ``run_tests.sh`` at the root of the +repository. This script provides many crucial functions for the project, +and also makes several otherwise complex tasks trivial for you as a +developer. + +First Run +========= + +If you start with a clean copy of the Horizon repository, the first thing +you should do is to run ``./run_tests.sh`` from the root of the repository. +This will do three things for you: + + #. Set up a virtual environment for ``openstack-dashboard`` using + ``openstack-dashboard/tools/install_venv.py``. + #. Set up an environment for ``horizon`` using + ``horizon/bootstrap.py`` and ``horizon/bin/buildout``. + #. Run the tests for both ``horizon`` and ``openstack-dashboard`` using + their respective environments and verify that evreything is working. + +Setting up both environments the first time can take several minutes, but only +needs to be done once. If dependencies are added in the future, updating the +environments will be necessary but not necessarily as time consuming. + +I just want to run the tests! +============================= + +Running both sets of unit tests quickly and easily is the main goal of this +script. All you need to do is:: + + ./run_tests.sh + +Yep, that's it. Everything else the script can do is optional. + +Give me metrics! +================ + +You can generate various reports and metrics using command line arguments +to ``run_tests.sh``. + +Coverage +-------- + +To run coverage reports:: + + ./run_tests.sh --coverage + +The reports are saved to ``./reports/`` and ``./coverage.xml``. + +PEP8 +---- + +You can check for PEP8 violations as well:: + + ./run_tests.sh --pep8 + +The results are saved to ``./pep8.txt``. + +PyLint +------ + +For more detailed code analysis you can run:: + + ./run_tests.sh --pylint + +The output will be saved in ``./pylint.txt``. + +Running the development server +============================== + +As an added bonus, you can run Django's development server directly from +the root of the repository with ``run_tests.sh`` like so:: + + ./run_tests.sh --runserver + +This is effectively just an alias for:: + + ./openstack-dashboard/tools/with_venv.sh ./openstack-dashboard/dashboard/manage.py runserver + +Generating the documentation +============================ + +You can build Horizon's documentation automatically by running:: + + ./run_tests.sh --docs + +The output is stored in ``./docs/build/html/``. + +Starting clean +============== + +If you ever want to start clean with a new environment for Horizon, you can +run:: + + ./run_tests.sh --force + +That will blow away the existing environments and create new ones for you. diff --git a/docs/source/ref/users.rst b/docs/source/ref/users.rst new file mode 100644 index 00000000..857358d1 --- /dev/null +++ b/docs/source/ref/users.rst @@ -0,0 +1,6 @@ +================= +Horizon User APIs +================= + +.. automodule:: horizon.users + :members: diff --git a/docs/source/ref/views.rst b/docs/source/ref/views.rst new file mode 100644 index 00000000..970609ca --- /dev/null +++ b/docs/source/ref/views.rst @@ -0,0 +1,12 @@ +============= +Horizon Views +============= + +Horizon ships with a number of pre-built views which are used within +Horizon and can also be reused in your applications. + +Auth +==== + +.. automodule:: horizon.views.auth + :members: diff --git a/docs/source/testing.rst b/docs/source/testing.rst new file mode 100644 index 00000000..a968ae50 --- /dev/null +++ b/docs/source/testing.rst @@ -0,0 +1,62 @@ +.. + Copyright 2011 OpenStack, LLC + 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. + +=============== +Testing Horizon +=============== + +How to run the tests +==================== + +Because Horizon is composed of both the ``horizon`` app and the +``openstack-dashboard`` reference project, there are in fact two sets of unit +tests. While they can be run individually without problem, there is an easier +way: + +Included at the root of the repository is the ``run_tests.sh`` script +which invokes both sets of tests, and optionally generates analyses on both +components in the process. This script is what what Jenkins uses to verify the +stability of the project, so you should make sure you run it and it passes +before you submit any pull requests/patches. + +To run the tests:: + + $ ./run_tests.sh + +.. seealso:: + + :doc:`ref/run_tests` + Full reference for the ``run_tests.sh`` script. + +How to write good tests +======================= + +Horizon uses Django's unit test machinery (which extends Python's ``unittest2`` +library) as the core of it's test suite. As such, all tests for the Python code +should be written as unit tests. No doctests please. + +A few pointers for writing good tests: + + * Write tests as you go--If you save them to the end you'll write less of + them and they'll often miss large chunks of code. + * Keep it as simple as possible--Make sure each test tests one thing + and tests it thoroughly. + * Think about all the possible inputs your code could have--It's usually + the edge cases that end up revealing bugs. + * Use ``coverage.py`` to find out what code is *not* being tested. + +In general new code without unit tests will not be accepted, and every bugfix +*must* include a regression test. |