Merge tag '2016.4.1' into debian/unstable
2016.4.1
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1bfce6e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+tests/build/
+*.swp
+*.pyc
+.ropeproject
\ No newline at end of file
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..ddab4aa
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=review.openstack.org
+port=29418
+project=openstack/salt-formula-horizon.git
+
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
new file mode 100644
index 0000000..80a6c16
--- /dev/null
+++ b/CHANGELOG.rst
@@ -0,0 +1,10 @@
+horizon formula
+===============
+
+2016.4.1 (2016-04-15)
+
+- second release
+
+0.0.1 (2015-08-03)
+
+- Initial formula setup
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8d968b6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..fc83783
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+DESTDIR=/
+SALTENVDIR=/usr/share/salt-formulas/env
+RECLASSDIR=/usr/share/salt-formulas/reclass
+FORMULANAME=$(shell grep name: metadata.yml|head -1|cut -d : -f 2|grep -Eo '[a-z0-9\-]*')
+
+all:
+ @echo "make install - Install into DESTDIR"
+ @echo "make test - Run tests"
+ @echo "make clean - Cleanup after tests run"
+
+install:
+ # Formula
+ [ -d $(DESTDIR)/$(SALTENVDIR) ] || mkdir -p $(DESTDIR)/$(SALTENVDIR)
+ cp -a $(FORMULANAME) $(DESTDIR)/$(SALTENVDIR)/
+ [ ! -d _modules ] || cp -a _modules $(DESTDIR)/$(SALTENVDIR)/
+ [ ! -d _states ] || cp -a _states $(DESTDIR)/$(SALTENVDIR)/ || true
+ # Metadata
+ [ -d $(DESTDIR)/$(RECLASSDIR)/service/$(FORMULANAME) ] || mkdir -p $(DESTDIR)/$(RECLASSDIR)/service/$(FORMULANAME)
+ cp -a metadata/service/* $(DESTDIR)/$(RECLASSDIR)/service/$(FORMULANAME)
+
+test:
+ [ ! -d tests ] || (cd tests; ./run_tests.sh)
+
+clean:
+ [ ! -d tests/build ] || rm -rf tests/build
+ [ ! -d build ] || rm -rf build
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..27511bd
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,369 @@
+
+=======
+Horizon
+=======
+
+Horizon is the canonical implementation of OpenStack’s Dashboard, which provides a web based user interface to OpenStack services including Nova, Swift, Keystone, etc.
+
+Sample pillars
+==============
+
+Packaged version of horizon
+---------------------------
+
+One horizon on server
+
+Simplest horizon setup with managed cloud-archive repo on ubuntu 12.04
+
+.. code-block:: yaml
+
+ linux:
+ system:
+ name: horizon
+ repo:
+ - cloudarchive-havana:
+ enabled: true
+ source: 'deb http://ubuntu-cloud.archive.canonical.com/ubuntu precise-updates/havana main'
+ pgpcheck: 0
+ horizon:
+ server:
+ manage_repo: true
+ enabled: true
+ secret_key: MEGASECRET
+ host:
+ name: cloud.lab.cz
+ cache:
+ engine: 'memcached'
+ host: '127.0.0.1'
+ port: 11211
+ prefix: 'CACHE_HORIZON'
+ identity:
+ engine: 'keystone'
+ host: '127.0.0.1'
+ port: 5000
+ api_version: 2
+ mail:
+ host: '127.0.0.1'
+
+Simple branded horizon
+
+.. code-block:: yaml
+
+ horizon:
+ server:
+ enabled: true
+ branding: 'OpenStack Company Dashboard'
+ default_dashboard: 'admin'
+ help_url: 'http://doc.domain.com'
+
+Horizon package setup with SSL
+
+.. code-block:: yaml
+
+ horizon:
+ server:
+ enabled: true
+ secret_key: MEGASECRET
+ version: juno
+ ssl:
+ enabled: true
+ authority: CA_Authority
+ host:
+ name: cloud.lab.cz
+ cache:
+ engine: 'memcached'
+ host: '127.0.0.1'
+ port: 11211
+ prefix: 'CACHE_HORIZON'
+ identity:
+ engine: 'keystone'
+ host: '127.0.0.1'
+ port: 5000
+ api_version: 2
+ mail:
+ host: '127.0.0.1'
+
+Multi-regional horizon setup
+
+.. code-block:: yaml
+
+ horizon:
+ server:
+ enabled: true
+ version: juno
+ secret_key: MEGASECRET
+ cache:
+ engine: 'memcached'
+ host: '127.0.0.1'
+ port: 11211
+ prefix: 'CACHE_HORIZON'
+ identity:
+ engine: 'keystone'
+ host: '127.0.0.1'
+ port: 5000
+ api_version: 2
+ mail:
+ host: '127.0.0.1'
+ regions:
+ - name: cluster1
+ address: http://cluster1.example.com:5000/v2.0
+ - name: cluster2
+ address: http://cluster2.example.com:5000/v2.0
+
+Horizon setup with sensu plugin
+
+.. code-block:: yaml
+
+ horizon:
+ server:
+ enabled: true
+ version: juno
+ sensu_api:
+ host: localhost
+ port: 4567
+ plugins:
+ - name: monitoring
+ app: horizon_monitoring
+ source:
+ type: git
+ address: git@repo1.robotice.cz:django/horizon-monitoring.git
+ rev: develop
+ - name: api-mask
+ app: api_mask
+ mask_url: 'custom-url.cz'
+ mask_protocol: 'http'
+ source:
+ type: git
+ address: git@repo1.robotice.cz:django/horizon-api-mask.git
+ rev: develop
+
+Sensu multi API
+
+.. code-block:: yaml
+
+ horizon:
+ server:
+ enabled: true
+ version: juno
+ sensu_api:
+ dc1:
+ host: localhost
+ port: 4567
+ dc2:
+ host: anotherhost
+ port: 4567
+
+Horizon setup with billometer plugin
+
+.. code-block:: yaml
+
+ horizon:
+ server:
+ enabled: true
+ version: juno
+ billometer_api:
+ host: localhost
+ port: 9753
+ api_version: 1
+ plugins:
+ - name: billing
+ app: horizon_billing
+ source:
+ type: git
+ address: git@repo1.robotice.cz:django/horizon-billing.git
+ rev: develop
+
+Horizon setup with contrail plugin
+
+.. code-block:: yaml
+
+ horizon:
+ server:
+ enabled: true
+ version: icehouse
+ plugins:
+ - name: contrail
+ app: contrail_openstack_dashboard
+ override: true
+ source:
+ type: git
+ address: git@repo1.robotice.cz:django/horizon-contrail.git
+ rev: develop
+
+Horizon setup with sentry log handler
+
+.. code-block:: yaml
+
+ horizon:
+ server:
+ enabled: true
+ version: juno
+ ...
+ logging:
+ engine: raven
+ dsn: http://pub:private@sentry1.test.cz/2
+
+Multisite with Git source
+-------------------------
+
+Simple Horizon setup from git repository
+
+.. code-block:: yaml
+
+ horizon:
+ server:
+ enabled: true
+ app:
+ default:
+ secret_key: MEGASECRET
+ source:
+ engine: git
+ address: https://github.com/openstack/horizon.git
+ rev: stable/havana
+ cache:
+ engine: 'memcached'
+ host: '127.0.0.1'
+ port: 11211
+ prefix: 'CACHE_DEFAULT'
+ identity:
+ engine: 'keystone'
+ host: '127.0.0.1'
+ port: 5000
+ api_version: 2
+ mail:
+ host: '127.0.0.1'
+
+Themed multisite setup
+
+.. code-block:: yaml
+
+ horizon:
+ server:
+ enabled: true
+ app:
+ openstack1c:
+ secret_key: MEGASECRET1
+ source:
+ engine: git
+ address: https://github.com/openstack/horizon.git
+ rev: stable/havana
+ plugin:
+ contrail:
+ app: contrail_openstack_dashboard
+ override: true
+ source:
+ type: git
+ address: git@repo1.robotice.cz:django/horizon-contrail.git
+ rev: develop
+ theme:
+ app: site1_theme
+ source:
+ type: git
+ address: git@repo1.domain.com:django/horizon-site1-theme.git
+ cache:
+ engine: 'memcached'
+ host: '127.0.0.1'
+ port: 11211
+ prefix: 'CACHE_SITE1'
+ identity:
+ engine: 'keystone'
+ host: '127.0.0.1'
+ port: 5000
+ api_version: 2
+ mail:
+ host: '127.0.0.1'
+ openstack2:
+ secret_key: MEGASECRET2
+ source:
+ engine: git
+ address: https://repo1.domain.com/openstack/horizon.git
+ rev: stable/icehouse
+ plugin:
+ contrail:
+ app: contrail_openstack_dashboard
+ override: true
+ source:
+ type: git
+ address: git@repo1.domain.com:django/horizon-contrail.git
+ rev: develop
+ monitoring:
+ app: horizon_monitoring
+ source:
+ type: git
+ address: git@domain.com:django/horizon-monitoring.git
+ rev: develop
+ theme:
+ app: bootswatch_theme
+ source:
+ type: git
+ address: git@repo1.robotice.cz:django/horizon-bootswatch-theme.git
+ rev: develop
+ cache:
+ engine: 'memcached'
+ host: '127.0.0.1'
+ port: 11211
+ prefix: 'CACHE_SITE2'
+ identity:
+ engine: 'keystone'
+ host: '127.0.0.1'
+ port: 5000
+ api_version: 3
+ mail:
+ host: '127.0.0.1'
+
+API versions override
+
+.. code-block:: yaml
+
+ horizon:
+ server:
+ enabled: true
+ app:
+ openstack_api_overrride:
+ secret_key: MEGASECRET1
+ api_versions:
+ identity: 3
+ volume: 2
+ source:
+ engine: git
+ address: https://github.com/openstack/horizon.git
+ rev: stable/havana
+
+Control dashboard behaviour
+
+.. code-block:: yaml
+
+ horizon:
+ server:
+ enabled: true
+ app:
+ openstack_dashboard_overrride:
+ secret_key: MEGASECRET1
+ dashboards:
+ settings:
+ enabled: true
+ project:
+ enabled: false
+ order: 10
+ admin:
+ enabled: false
+ order: 20
+ source:
+ engine: git
+ address: https://github.com/openstack/horizon.git
+ rev: stable/juno
+
+Read more
+=========
+
+* https://github.com/openstack/horizon
+* http://dijks.wordpress.com/2012/07/06/how-to-change-screen-resolution-of-novnc-client-in-openstack-essex-dashboard-nova-horizon/
+
+
+Things to improve
+=================
+
+* ALLOWED_HOSTS - do not use * - introduce parameters
+* CACHES - configure caching engine - is it not allowed by default?
+* SESSION_ENGINE - change it from signed cookie to something else
+* policy files - look into these files and think of further configuration/parametrisation
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..1bad316
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+2016.4.1
diff --git a/doc/source/conf.py b/doc/source/conf.py
new file mode 100644
index 0000000..9141a4c
--- /dev/null
+++ b/doc/source/conf.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+
+sys.path.insert(0, os.path.abspath('../..'))
+# -- General configuration ----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+]
+
+# autodoc generation is a bit aggressive and a nuisance when doing heavy
+# text edit cycles.
+# execute "export SPHINX_DEBUG=1" in your terminal to disable
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'salt-formula-horizon'
+copyright = u'2015, OpenStack Foundation'
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+add_module_names = True
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# -- Options for HTML output --------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+# html_theme_path = ["."]
+# html_theme = '_theme'
+# html_static_path = ['static']
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = '%sdoc' % project
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass
+# [howto/manual]).
+latex_documents = [
+ ('index',
+ '%s.tex' % project,
+ u'%s Documentation' % project,
+ u'OpenStack Foundation', 'manual'),
+]
+
+# Example configuration for intersphinx: refer to the Python standard library.
+# intersphinx_mapping = {'http://docs.python.org/': None}
diff --git a/doc/source/index.rst b/doc/source/index.rst
new file mode 100644
index 0000000..a6210d3
--- /dev/null
+++ b/doc/source/index.rst
@@ -0,0 +1 @@
+.. include:: ../../README.rst
diff --git a/horizon/files/enabled/admin.py b/horizon/files/enabled/admin.py
new file mode 100644
index 0000000..6e358ff
--- /dev/null
+++ b/horizon/files/enabled/admin.py
@@ -0,0 +1,13 @@
+
+ENABLED = {{enabled | python}}
+
+{%- if enabled %}
+
+DASHBOARD = 'admin'
+
+# A list of applications to be added to INSTALLED_APPS.
+ADD_INSTALLED_APPS = [
+ 'openstack_dashboard.dashboards.admin',
+]
+
+{%- endif %}
diff --git a/horizon/files/enabled/admin_dashboard_disable.py b/horizon/files/enabled/admin_dashboard_disable.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/horizon/files/enabled/admin_dashboard_disable.py
diff --git a/horizon/files/enabled/api_mask.py b/horizon/files/enabled/api_mask.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/horizon/files/enabled/api_mask.py
diff --git a/horizon/files/enabled/billing.py b/horizon/files/enabled/billing.py
new file mode 100644
index 0000000..24c3054
--- /dev/null
+++ b/horizon/files/enabled/billing.py
@@ -0,0 +1,18 @@
+
+DASHBOARD = 'billing'
+
+ENABLED = True
+DEFAULT = True
+
+ADD_INSTALLED_APPS = [
+ 'horizon_billing',
+]
+
+ADD_SCSS_FILES = [
+ 'billing/scss/billing.scss'
+]
+
+ADD_JS_FILES = [
+ 'billing/js/nv.d3.min.js'
+]
+
diff --git a/horizon/files/enabled/contrail.py b/horizon/files/enabled/contrail.py
new file mode 100644
index 0000000..25572af
--- /dev/null
+++ b/horizon/files/enabled/contrail.py
@@ -0,0 +1,9 @@
+# The name of the dashboard to be added to HORIZON['dashboards']. Required.
+DASHBOARD = 'contrail'
+# If set to True, this dashboard will be set as the default dashboard.
+DEFAULT = False
+# A dictionary of exception classes to be added to HORIZON['exceptions'].
+ADD_EXCEPTIONS = {}
+# A list of applications to be added to INSTALLED_APPS.
+ADD_INSTALLED_APPS = ['contrail_openstack_dashboard.contrail']
+
diff --git a/horizon/files/enabled/contrib.py b/horizon/files/enabled/contrib.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/horizon/files/enabled/contrib.py
diff --git a/horizon/files/enabled/heat.py b/horizon/files/enabled/heat.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/horizon/files/enabled/heat.py
diff --git a/horizon/files/enabled/heat_extension.py b/horizon/files/enabled/heat_extension.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/horizon/files/enabled/heat_extension.py
@@ -0,0 +1 @@
+
diff --git a/horizon/files/enabled/helpdesk.py b/horizon/files/enabled/helpdesk.py
new file mode 100644
index 0000000..c367336
--- /dev/null
+++ b/horizon/files/enabled/helpdesk.py
@@ -0,0 +1,10 @@
+
+DASHBOARD = 'helpdesk'
+
+ENABLED = True
+
+DEFAULT = True
+
+ADD_INSTALLED_APPS = [
+ 'helpdesk_dashboard',
+]
diff --git a/horizon/files/enabled/horizon_override.py b/horizon/files/enabled/horizon_override.py
new file mode 100644
index 0000000..28ac6e5
--- /dev/null
+++ b/horizon/files/enabled/horizon_override.py
@@ -0,0 +1,28 @@
+{%- from "horizon/map.jinja" import server with context %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+
+ALLOWED_HOSTS = ['*']
+
+{%- if app.ssl is defined %}
+{%- if app.ssl.enabled %}
+SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
+CSRF_COOKIE_SECURE = True
+SESSION_COOKIE_SECURE = True
+{%- endif %}
+{%- endif %}
+
+SECRET_KEY = '{{ app.secret_key }}'
+
+{% include "horizon/files/local_settings/_keystone_settings.py" %}
+
+{%- if app.plugin.merlin_panels is defined %}
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': '/srv/horizon/sites/{{ app_name }}/database.db',
+ 'TEST_NAME': 'test_db:',
+ }
+}
+
+{%- endif %}
diff --git a/horizon/files/enabled/horizon_overrides.py b/horizon/files/enabled/horizon_overrides.py
new file mode 100644
index 0000000..4595455
--- /dev/null
+++ b/horizon/files/enabled/horizon_overrides.py
@@ -0,0 +1,4 @@
+
+ADD_INSTALLED_APPS = [
+ 'horizon_overrides',
+]
diff --git a/horizon/files/enabled/horizon_theme.py b/horizon/files/enabled/horizon_theme.py
new file mode 100644
index 0000000..7a08161
--- /dev/null
+++ b/horizon/files/enabled/horizon_theme.py
@@ -0,0 +1,9 @@
+# The name of the dashboard to be added to HORIZON['dashboards']. Required.
+DASHBOARD = 'theme'
+# If set to True, this dashboard will be set as the default dashboard.
+DEFAULT = False
+# A dictionary of exception classes to be added to HORIZON['exceptions'].
+ADD_EXCEPTIONS = {}
+# A list of applications to be added to INSTALLED_APPS.
+ADD_INSTALLED_APPS = ['openstack_dashboard.dashboards.theme']
+#, 'horizon_overrides']
\ No newline at end of file
diff --git a/horizon/files/enabled/identity.py b/horizon/files/enabled/identity.py
new file mode 100644
index 0000000..273b659
--- /dev/null
+++ b/horizon/files/enabled/identity.py
@@ -0,0 +1,14 @@
+
+ENABLED = {{enabled | python}}
+
+{%- if enabled %}
+
+DASHBOARD = 'identity'
+# If set to True, this dashboard will be set as the default dashboard.
+DEFAULT = False
+# A dictionary of exception classes to be added to HORIZON['exceptions'].
+ADD_EXCEPTIONS = {}
+# A list of applications to be added to INSTALLED_APPS.
+ADD_INSTALLED_APPS = ['openstack_dashboard.dashboards.identity']
+
+{%- endif %}
diff --git a/horizon/files/enabled/merlin_panels.py b/horizon/files/enabled/merlin_panels.py
new file mode 100644
index 0000000..3fd1d46
--- /dev/null
+++ b/horizon/files/enabled/merlin_panels.py
@@ -0,0 +1,17 @@
+# The name of the panel to be added to HORIZON_CONFIG. Required.
+PANEL = 'mistral'
+# The name of the dashboard the PANEL associated with. Required.
+PANEL_DASHBOARD = 'project'
+# The name of the panel group the PANEL is associated with.
+PANEL_GROUP = 'orchestration'
+
+ADD_INSTALLED_APPS = ['merlin', 'mistral']
+
+# Python panel class of the PANEL to be added.
+ADD_PANEL = 'mistral.panel.MistralPanel'
+
+ADD_ANGULAR_MODULES = ['merlin', 'mistral']
+ADD_JS_FILES = ['merlin/js/custom-libs/ui-bootstrap-tpls-0.12.1.js',
+ 'merlin/js/merlin.init.js',
+ 'merlin/js/merlin.templates.js',
+ 'mistral/js/mistral.init.js']
diff --git a/horizon/files/enabled/mistral_dashboard.py b/horizon/files/enabled/mistral_dashboard.py
new file mode 100644
index 0000000..dba10fe
--- /dev/null
+++ b/horizon/files/enabled/mistral_dashboard.py
@@ -0,0 +1,8 @@
+
+DASHBOARD = 'mistral'
+
+ADD_INSTALLED_APPS = ['mistraldashboard']
+
+DEFAULT = True
+
+ADD_EXCEPTIONS = {}
\ No newline at end of file
diff --git a/horizon/files/enabled/monitoring_dashboard.py b/horizon/files/enabled/monitoring_dashboard.py
new file mode 100644
index 0000000..c22c613
--- /dev/null
+++ b/horizon/files/enabled/monitoring_dashboard.py
@@ -0,0 +1,8 @@
+
+DASHBOARD = 'monitoring'
+
+ENABLED = True
+
+ADD_INSTALLED_APPS = [
+ 'horizon_monitoring'
+]
diff --git a/horizon/files/enabled/murano_dashboard.py b/horizon/files/enabled/murano_dashboard.py
new file mode 100644
index 0000000..ee4a727
--- /dev/null
+++ b/horizon/files/enabled/murano_dashboard.py
@@ -0,0 +1,17 @@
+from muranodashboard import exceptions
+
+# The name of the dashboard to be added to HORIZON['dashboards']. Required.
+DASHBOARD = 'murano'
+
+# If set to True, this dashboard will not be added to the settings.
+DISABLED = False
+
+ADD_INSTALLED_APPS = [
+ 'muranodashboard',
+]
+
+ADD_EXCEPTIONS = {
+ 'recoverable': exceptions.RECOVERABLE,
+ 'not_found': exceptions.NOT_FOUND,
+ 'unauthorized': exceptions.UNAUTHORIZED,
+}
diff --git a/horizon/files/enabled/network_allocation_panel.py b/horizon/files/enabled/network_allocation_panel.py
new file mode 100644
index 0000000..dd194d4
--- /dev/null
+++ b/horizon/files/enabled/network_allocation_panel.py
@@ -0,0 +1,11 @@
+# Add to installed apps
+ADD_INSTALLED_APPS = ['horizon_network_allocation_panel']
+# The slug of the panel to be added to HORIZON_CONFIG. Required.
+PANEL = 'network_allocation'
+# The slug of the dashboard the PANEL associated with. Required.
+PANEL_DASHBOARD = 'admin'
+# The slug of the panel group the PANEL is associated with.
+PANEL_GROUP = 'admin'
+
+# Python panel class of the PANEL to be added.
+ADD_PANEL = 'horizon_network_allocation_panel.panel.NetworkAllocationPanel'
diff --git a/horizon/files/enabled/project.py b/horizon/files/enabled/project.py
new file mode 100644
index 0000000..e32cc57
--- /dev/null
+++ b/horizon/files/enabled/project.py
@@ -0,0 +1,49 @@
+
+ENABLED = {{enabled | python}}
+
+{%- if enabled %}
+
+# The slug of the dashboard to be added to HORIZON['dashboards']. Required.
+DASHBOARD = 'project'
+# If set to True, this dashboard will be set as the default dashboard.
+DEFAULT = True
+# A dictionary of exception classes to be added to HORIZON['exceptions'].
+ADD_EXCEPTIONS = {}
+# A list of applications to be added to INSTALLED_APPS.
+ADD_INSTALLED_APPS = ['openstack_dashboard.dashboards.project']
+
+ADD_ANGULAR_MODULES = ['hz.dashboard']
+
+LAUNCH_INST = 'dashboard/launch-instance/'
+
+ADD_JS_FILES = [
+ 'dashboard/dashboard.module.js',
+ 'dashboard/workflow/workflow.js',
+ 'dashboard/cloud-services/cloud-services.js',
+ LAUNCH_INST + 'launch-instance.js',
+ LAUNCH_INST + 'launch-instance.model.js',
+ LAUNCH_INST + 'source/source.js',
+ LAUNCH_INST + 'flavor/flavor.js',
+ LAUNCH_INST + 'flavor/select-flavor-table.js',
+ LAUNCH_INST + 'network/network.js',
+ LAUNCH_INST + 'security-groups/security-groups.js',
+ LAUNCH_INST + 'keypair/keypair.js',
+ LAUNCH_INST + 'configuration/configuration.js',
+ LAUNCH_INST + 'configuration/load-edit.js',
+]
+
+ADD_JS_SPEC_FILES = [
+ 'dashboard/dashboard.module.spec.js',
+ 'dashboard/workflow/workflow.spec.js',
+ 'dashboard/cloud-services/cloud-services.spec.js',
+ LAUNCH_INST + 'launch-instance.spec.js',
+ LAUNCH_INST + 'launch-instance.model.spec.js',
+ LAUNCH_INST + 'source/source.spec.js',
+ LAUNCH_INST + 'flavor/flavor.spec.js',
+ LAUNCH_INST + 'network/network.spec.js',
+ LAUNCH_INST + 'security-groups/security-groups.spec.js',
+ LAUNCH_INST + 'keypair/keypair.spec.js',
+ LAUNCH_INST + 'configuration/configuration.spec.js',
+]
+
+{%- endif %}
diff --git a/horizon/files/enabled/rally_dashboard.py b/horizon/files/enabled/rally_dashboard.py
new file mode 100644
index 0000000..fbc101e
--- /dev/null
+++ b/horizon/files/enabled/rally_dashboard.py
@@ -0,0 +1,3 @@
+
+DASHBOARD = 'benchmark'
+ADD_INSTALLED_APPS = ['benchmark_dashboard']
diff --git a/horizon/files/enabled/sahara_dashboard.py b/horizon/files/enabled/sahara_dashboard.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/horizon/files/enabled/sahara_dashboard.py
diff --git a/horizon/files/enabled/settings.py b/horizon/files/enabled/settings.py
new file mode 100644
index 0000000..5646377
--- /dev/null
+++ b/horizon/files/enabled/settings.py
@@ -0,0 +1,2 @@
+
+ENABLED = {{enabled | python}}
diff --git a/horizon/files/enabled/telemetry_dashboard.py b/horizon/files/enabled/telemetry_dashboard.py
new file mode 100644
index 0000000..26d2e1d
--- /dev/null
+++ b/horizon/files/enabled/telemetry_dashboard.py
@@ -0,0 +1,20 @@
+
+DASHBOARD = 'telemetry'
+
+ENABLED = True
+
+ADD_INSTALLED_APPS = [
+ 'horizon_telemetry'
+]
+
+ADD_SCSS_FILES = [
+ 'telemetry/scss/telemetry.scss'
+]
+
+ADD_JS_FILES = [
+ 'telemetry/js/cubism.js',
+ 'telemetry/js/graph_utils.js',
+ 'telemetry/js/concentric_gauge_area.js',
+ 'telemetry/js/nv.d3.min.js'
+]
+
diff --git a/horizon/files/gunicorn_start b/horizon/files/gunicorn_start
new file mode 100644
index 0000000..876ff84
--- /dev/null
+++ b/horizon/files/gunicorn_start
@@ -0,0 +1,30 @@
+#!/bin/bash
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+
+NAME="horizon_{{ app_name }}"
+DJANGODIR=/srv/horizon/sites/{{ app_name }}
+USER=horizon
+GROUP=horizon
+NUM_WORKERS={{ app.get('workers', 3) }}
+DJANGO_SETTINGS_MODULE="{{ app.get('dashboard', 'openstack') }}_dashboard.settings"
+DJANGO_WSGI_MODULE=wsgi
+
+# Activate the virtual environment
+cd $DJANGODIR
+source /srv/horizon/sites/{{ app_name }}/bin/activate
+export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
+export PYTHONPATH=$DJANGODIR:{% for plugin_name, plugin in app.plugin.iteritems() %}/srv/horizon/sites/{{ app_name }}/plugins/{{ plugin_name }}:{% endfor %}$PYTHONPATH
+{%- if app.mistral_api is defined %}
+export OS_MISTRAL_URL=http://{{ app.mistral_api.host }}:{{ app.mistral_api.port }}/v2
+{%- endif %}
+
+# Start your Django Unicorn
+# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
+exec /srv/horizon/sites/{{ app_name }}/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
+ --name $NAME \
+ --workers $NUM_WORKERS \
+ --user=$USER --group=$GROUP \
+ --log-level=debug \
+ --log-file=/var/log/horizon/{{ app_name }}_gunicorn.log \
+ --bind={{ app.bind.address }}:{{ app.bind.port }} \
+ --timeout=600
\ No newline at end of file
diff --git a/horizon/files/horizon_settings/_glance_settings.py b/horizon/files/horizon_settings/_glance_settings.py
new file mode 100644
index 0000000..67fa3c3
--- /dev/null
+++ b/horizon/files/horizon_settings/_glance_settings.py
@@ -0,0 +1,37 @@
+{%- from "horizon/map.jinja" import server with context %}
+
+{%- if server.app is defined %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+{%- else %}
+{%- set app = salt['pillar.get']('horizon:server') %}
+{%- endif %}
+
+# The OPENSTACK_IMAGE_BACKEND settings can be used to customize features
+# in the OpenStack Dashboard related to the Image service, such as the list
+# of supported image formats.
+OPENSTACK_IMAGE_BACKEND = {
+ 'image_formats': [
+ ('', ''),
+ ('aki', _('AKI - Amazon Kernel Image')),
+ ('ami', _('AMI - Amazon Machine Image')),
+ ('ari', _('ARI - Amazon Ramdisk Image')),
+ ('iso', _('ISO - Optical Disk Image')),
+ ('qcow2', _('QCOW2 - QEMU Emulator')),
+ ('raw', _('Raw')),
+ ('vdi', _('VDI')),
+ ('vhd', _('VHD')),
+ ('vmdk', _('VMDK')),
+ ('docker', _('Docker Container'))
+ ]
+}
+
+# The IMAGE_CUSTOM_PROPERTY_TITLES settings is used to customize the titles for
+# image custom property attributes that appear on image detail pages.
+IMAGE_CUSTOM_PROPERTY_TITLES = {
+ "architecture": _("Architecture"),
+ "kernel_id": _("Kernel ID"),
+ "ramdisk_id": _("Ramdisk ID"),
+ "image_state": _("Euca2ools state"),
+ "project_id": _("Project ID"),
+ "image_type": _("Image Type")
+}
diff --git a/horizon/files/horizon_settings/_horizon_settings.py b/horizon/files/horizon_settings/_horizon_settings.py
new file mode 100644
index 0000000..78bf00d
--- /dev/null
+++ b/horizon/files/horizon_settings/_horizon_settings.py
@@ -0,0 +1,160 @@
+{%- from "horizon/map.jinja" import server with context %}
+
+{%- if server.app is defined %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+{%- else %}
+{%- set app = salt['pillar.get']('horizon:server') %}
+{%- endif %}
+
+# Specify a regular expression to validate user passwords.
+# HORIZON_CONFIG["password_validator"] = {
+# "regex": '.*',
+# "help_text": _("Your password does not meet the requirements.")
+# }
+
+# Turn off browser autocompletion for the login form if so desired.
+# HORIZON_CONFIG["password_autocomplete"] = "off"
+
+# The Horizon Policy Enforcement engine uses these values to load per service
+# policy rule files. The content of these files should match the files the
+# OpenStack services are using to determine role based access control in the
+# target installation.
+
+{%- if server.session_timeout is defined %}
+SESSION_TIMEOUT = {{ server.session_timeout }}
+{%- endif %}
+
+# Path to directory containing policy.json files
+#POLICY_FILES_PATH = os.path.join(ROOT_PATH, "conf")
+# Map of local copy of service policy files
+POLICY_FILES = {
+ 'identity': 'keystone_policy.json',
+ 'compute': 'nova_policy.json',
+ 'image': 'glance_policy.json',
+ 'volume': 'cinder_policy.json'
+}
+
+LOGGING = {
+ 'version': 1,
+ # When set to True this will disable all logging except
+ # for loggers specified in this configuration dictionary. Note that
+ # if nothing is specified here and disable_existing_loggers is True,
+ # django.db.backends will still log unless it is disabled explicitly.
+ 'disable_existing_loggers': False,
+ 'handlers': {
+ 'null': {
+ 'level': 'DEBUG',
+ 'class': 'django.utils.log.NullHandler',
+ },
+ 'console': {
+ # Set the level to "DEBUG" for verbose output logging.
+ 'level': 'INFO',
+ 'class': 'logging.StreamHandler',
+ },
+ 'file': {
+ 'level': 'DEBUG',
+ 'class': 'logging.FileHandler',
+ {%- if app_name is defined %}
+ 'filename': '/var/log/horizon/{{ app_name }}_horizon.log',
+ {%- else %}
+ 'filename': '/var/log/horizon/horizon.log',
+ {%- endif %}
+ },
+ },
+ 'loggers': {
+ # Logging from django.db.backends is VERY verbose, send to null
+ # by default.
+ 'django.db.backends': {
+ 'handlers': ['null'],
+ 'propagate': False,
+ },
+ 'requests': {
+ 'handlers': ['null'],
+ 'propagate': False,
+ },
+ 'horizon': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'openstack_dashboard': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'novaclient': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'cinderclient': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'keystoneclient': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'glanceclient': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'neutronclient': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'heatclient': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'ceilometerclient': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'troveclient': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'mistralclient': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'swiftclient': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'openstack_auth': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'scss.expression': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'nose.plugins.manager': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'django': {
+ 'handlers': ['file'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ },
+ 'iso8601': {
+ 'handlers': ['null'],
+ 'propagate': False,
+ },
+ }
+}
diff --git a/horizon/files/horizon_settings/_keystone_settings.py b/horizon/files/horizon_settings/_keystone_settings.py
new file mode 100644
index 0000000..5b4987f
--- /dev/null
+++ b/horizon/files/horizon_settings/_keystone_settings.py
@@ -0,0 +1,82 @@
+{%- from "horizon/map.jinja" import server with context %}
+
+{%- if server.app is defined %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+{%- else %}
+{%- set app = salt['pillar.get']('horizon:server') %}
+{%- endif %}
+
+# Overrides for OpenStack API versions. Use this setting to force the
+# OpenStack dashboard to use a specfic API version for a given service API.
+# NOTE: The version should be formatted as it appears in the URL for the
+# service API. For example, The identity service APIs have inconsistent
+# use of the decimal point, so valid options would be "2.0" or "3".
+{%- if app.api_versions is defined %}
+OPENSTACK_API_VERSIONS = {
+{%- for key, value in app.api_versions.iteritems() %}
+ "{{ key }}": {{ value }}{% if not loop.last %},{% endif %}
+{%- endfor %}
+}
+{%- endif %}
+# Set this to True if running on multi-domain model. When this is enabled, it
+# will require user to enter the Domain name in addition to username for login.
+# OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = False
+
+# Overrides the default domain used when running on single-domain model
+# with Keystone V3. All entities will be created in the default domain.
+# OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = 'Default'
+
+# For multiple regions uncomment this configuration, and add (endpoint, title).
+# AVAILABLE_REGIONS = [
+# ('http://cluster1.example.com:5000/v2.0', 'cluster1'),
+# ('http://cluster2.example.com:5000/v2.0', 'cluster2'),
+# ]
+
+OPENSTACK_HOST = "{{ app.identity.host }}"
+{%- if app.get('api_versions', {}).identity is defined %}
+OPENSTACK_KEYSTONE_URL = "http{% if app.identity.encryption == 'ssl' %}s{% endif %}://%s:{{ app.identity.port }}/v{{ app.api_versions.identity }}" % OPENSTACK_HOST
+{%- else %}
+OPENSTACK_KEYSTONE_URL = "http{% if app.identity.encryption == 'ssl' %}s{% endif %}://%s:{{ app.identity.port }}/v2.0" % OPENSTACK_HOST
+{%- endif %}
+
+{%- if app.get('multidomain', false) %}
+OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True
+OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = 'default'
+{%- endif %}
+
+OPENSTACK_KEYSTONE_DEFAULT_ROLE = "Member"
+
+# Disable SSL certificate checks (useful for self-signed certificates):
+{%- if app.identity.encryption == 'ssl' %}
+OPENSTACK_SSL_NO_VERIFY = True
+{%- endif %}
+
+# The CA certificate to use to verify SSL connections
+# OPENSTACK_SSL_CACERT = '/path/to/cacert.pem'
+
+# OPENSTACK_ENDPOINT_TYPE specifies the endpoint type to use for the endpoints
+# in the Keystone service catalog. Use this setting when Horizon is running
+# external to the OpenStack environment. The default is 'publicURL'.
+OPENSTACK_ENDPOINT_TYPE = "publicURL"
+
+# SECONDARY_ENDPOINT_TYPE specifies the fallback endpoint type to use in the
+# case that OPENSTACK_ENDPOINT_TYPE is not present in the endpoints
+# in the Keystone service catalog. Use this setting when Horizon is running
+# external to the OpenStack environment. The default is None. This
+# value should differ from OPENSTACK_ENDPOINT_TYPE if used.
+#SECONDARY_ENDPOINT_TYPE = "publicURL"
+
+# The OPENSTACK_KEYSTONE_BACKEND settings can be used to identify the
+# capabilities of the auth backend for Keystone.
+# If Keystone has been configured to use LDAP as the auth backend then set
+# can_edit_user to False and name to 'ldap'.
+#
+# TODO(tres): Remove these once Keystone has an API to identify auth backend.
+OPENSTACK_KEYSTONE_BACKEND = {
+ 'name': 'native',
+ 'can_edit_user': True,
+ 'can_edit_group': True,
+ 'can_edit_project': True,
+ 'can_edit_domain': True,
+ 'can_edit_role': True
+}
diff --git a/horizon/files/horizon_settings/_local_settings.py b/horizon/files/horizon_settings/_local_settings.py
new file mode 100644
index 0000000..8148ddc
--- /dev/null
+++ b/horizon/files/horizon_settings/_local_settings.py
@@ -0,0 +1,193 @@
+{%- from "horizon/map.jinja" import server with context %}
+
+{%- if server.app is defined %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+{%- else %}
+{%- set app = salt['pillar.get']('horizon:server') %}
+{%- endif %}
+
+DEBUG = {% if app.get('development', False) %}True{% else %}False{% endif %}
+
+TEMPLATE_DEBUG = DEBUG
+
+ALLOWED_HOSTS = ['*']
+
+{%- if app.ssl is defined %}
+{%- if app.ssl.enabled %}
+SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
+CSRF_COOKIE_SECURE = True
+SESSION_COOKIE_SECURE = True
+{%- endif %}
+{%- endif %}
+
+AUTHENTICATION_URLS = ['openstack_auth.urls']
+
+LOCAL_PATH = os.path.dirname(os.path.abspath(__file__))
+
+SECRET_KEY = '{{ app.secret_key }}'
+
+CACHES = {
+ 'default': {
+ 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
+ {%- if app.cache.members is defined %}
+ 'LOCATION': "{%- for member in app.cache.members %}{{ member.host }}:{{ member.port }}{% if not loop.last %};{% endif %}{%- endfor %}"
+ {%- else %}
+ 'LOCATION': '{{ app.cache.host }}:{{ app.cache.port }}',
+ {%- endif %}
+ }
+}
+
+# Send email to the console by default
+EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
+# Or send them to /dev/null
+#EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'
+
+# Configure these for your outgoing email host
+# EMAIL_HOST = 'smtp.my-company.com'
+# EMAIL_PORT = 25
+# EMAIL_HOST_USER = 'djangomail'
+# EMAIL_HOST_PASSWORD = 'top-secret!'
+
+# The number of objects (Swift containers/objects or images) to display
+# on a single page before providing a paging element (a "more" link)
+# to paginate results.
+API_RESULT_LIMIT = 1000
+API_RESULT_PAGE_SIZE = 20
+
+# The timezone of the server. This should correspond with the timezone
+# of your entire OpenStack installation, and hopefully be in UTC.
+TIME_ZONE = "UTC"
+
+COMPRESS_OFFLINE = True
+
+# Trove user and database extension support. By default support for
+# creating users and databases on database instances is turned on.
+# To disable these extensions set the permission here to something
+# unusable such as ["!"].
+# TROVE_ADD_USER_PERMS = []
+# TROVE_ADD_DATABASE_PERMS = []
+
+{%- if app.uenc_api is defined %}
+UENC_HOST = '{{ app.uenc_api.host }}'
+UENC_PORT = '{{ app.uenc_api.port }}'
+{%- endif %}
+
+{%- if app.control_nodes is defined %}
+OPENSTACK_CONTROL_NODES = {{ app.control_nodes|python }}
+{%- endif %}
+
+{%- if app.sensu_api is defined %}
+{%- if app.sensu_api.host is defined %}
+SENSU_HOST = '{{ app.sensu_api.host }}'
+SENSU_PORT = '{{ app.sensu_api.port }}'
+{%- else %}
+SENSU_API = {{ app.sensu_api|python }}
+def check_filter(check):
+ return ":".join(check['name'].split("_")[1:-1])
+SENSU_CHECK_FILTER = check_filter
+{%- endif %}
+{%- endif %}
+
+{%- if app.kedb_api is defined %}
+KEDB_HOST = '{{ app.kedb_api.host }}'
+KEDB_PORT = '{{ app.kedb_api.port }}'
+{%- endif %}
+
+{%- if app.cold_api is defined %}
+COLD_HOST = '{{ app.cold_api.host }}'
+COLD_PORT = '{{ app.cold_api.port }}'
+{%- endif %}
+
+{%- if app.robotice_api is defined %}
+ROBOTICE_HOST = '{{ app.robotice_api.host }}'
+ROBOTICE_PORT = '{{ app.robotice_api.port }}'
+{%- endif %}
+
+{%- if app.csb_api is defined %}
+CSB_HOST = '{{ app.csb_api.host }}'
+CSB_PORT = '{{ app.csb_api.port }}'
+AUTHENTICATION_BACKENDS = ('csb_auth.backend.CSBackend',)
+{%- endif %}
+
+{%- if app.murano_api is defined %}
+MURANO_API_URL = "http://{{ app.murano_api.host }}:{{ app.murano_api.port }}"
+SESSION_ENGINE = "django.contrib.sessions.backends.cache"
+# TODO(majklk) make this configurable
+MURANO_REPO_URL = 'http://storage.apps.openstack.org/'
+# this folder muset exists before start
+#METADATA_CACHE_DIR = '/var/cache/muranodashboard-cache'
+{%- endif %}
+
+{%- if app.helpdesk_api is defined %}
+HELPDESK_HOST = '{{ app.helpdesk_api.host }}'
+HELPDESK_PORT = '{{ app.helpdesk_api.port }}'
+{%- endif %}
+
+{%- for plugin_name, plugin in app.get('plugin', {}).iteritems() %}
+
+{%- if plugin.database is defined %}
+{%- set db = plugin.database %}
+RALLY_DB = "{{ db.engine }}://{{ db.username }}:{{ db.password }}@{{ db.get('host', '127.0.0.1') }}/{{ db.name }}"
+{%- endif %}
+
+{%- if plugin.override is defined %}
+HORIZON_CONFIG['customization_module'] = '{{ plugin.app }}.overrides'
+{%- endif %}
+
+{%- if plugin.mask_url is defined %}
+API_MASK_URL = '{{ plugin.mask_url }}'
+{%- endif %}
+
+{%- if plugin.config is defined %}
+{{ plugin_name|upper }}_CONFIG = {{ plugin.config|python }}
+{%- endif %}
+
+{%- if plugin.mask_protocol is defined %}
+API_MASK_PROTOCOL = '{{ plugin.mask_protocol }}'
+{%- endif %}
+
+{%- if plugin.metric is defined %}
+{%- if plugin.metric.engine == "graphite" %}
+GRAPHITE_HOST = "{{ plugin.metric.host }}"
+GRAPHITE_PORT = "{{ plugin.metric.port }}"
+GRAPHITE_ENDPOINT = 'http://%s:%s/' % (GRAPHITE_HOST, GRAPHITE_PORT)
+{%- endif %}
+{%- endif %}
+
+{%- if plugin.overrides is defined %}
+OVERRIDES = (
+ {%- for override in plugin.overrides %}
+ "{{ override }}",
+ {%- endfor %}
+)
+{%- endif %}
+
+{%- if plugin_name == "sahara" %}
+SAHARA_USE_NEUTRON = True
+AUTO_ASSIGNMENT_ENABLED = False
+{%- endif %}
+
+{%- if plugin_name == "contrail" and app.get("version", "juno") == "juno" %}
+from openstack_dashboard.settings import STATICFILES_DIRS
+import xstatic
+from contrail_openstack_dashboard.openstack_dashboard.xstatic.pkg import contrail
+
+pkg = __import__('contrail_openstack_dashboard.openstack_dashboard')
+
+STATICFILES_DIRS.append(('dashboard/js/', xstatic.main.XStatic(contrail).base_dir))
+
+{%- endif %}
+
+{%- if plugin.urls is defined %}
+AUTHENTICATION_URLS += {{ plugin.urls|python }}
+{%- endif %}
+
+{%- endfor %}
+
+{%- if app.logging is defined %}
+RAVEN_CONFIG = {
+ 'dsn': '{{ app.logging.dsn }}',
+}
+{%- endif %}
+
+SITE_BRANDING = '{{ app.get('branding', 'OpenStack Dashboard') }}'
diff --git a/horizon/files/horizon_settings/_neutron_settings.py b/horizon/files/horizon_settings/_neutron_settings.py
new file mode 100644
index 0000000..c714b7c
--- /dev/null
+++ b/horizon/files/horizon_settings/_neutron_settings.py
@@ -0,0 +1,134 @@
+{%- from "horizon/map.jinja" import server with context %}
+
+{%- if server.app is defined %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+{%- else %}
+{%- set app = salt['pillar.get']('horizon:server') %}
+{%- endif %}
+
+# Disable simplified floating IP address management for deployments with
+# multiple floating IP pools or complex network requirements.
+# HORIZON_CONFIG["simple_ip_management"] = False
+
+# The OPENSTACK_NEUTRON_NETWORK settings can be used to enable optional
+# services provided by neutron. Options currenly available are load
+# balancer service, security groups, quotas, VPN service.
+OPENSTACK_NEUTRON_NETWORK = {
+ 'enable_lb': True,
+ 'enable_firewall': False,
+ 'enable_quotas': True,
+ 'enable_security_group': True,
+ 'enable_vpn': False,
+ # The profile_support option is used to detect if an externa lrouter can be
+ # configured via the dashboard. When using specific plugins the
+ # profile_support can be turned on if needed.
+ 'profile_support': None,
+ #'profile_support': 'cisco',
+}
+
+# 'direction' should not be specified for all_tcp/udp/icmp.
+# It is specified in the form.
+SECURITY_GROUP_RULES = {
+ 'all_tcp': {
+ 'name': 'ALL TCP',
+ 'ip_protocol': 'tcp',
+ 'from_port': '1',
+ 'to_port': '65535',
+ },
+ 'all_udp': {
+ 'name': 'ALL UDP',
+ 'ip_protocol': 'udp',
+ 'from_port': '1',
+ 'to_port': '65535',
+ },
+ 'all_icmp': {
+ 'name': 'ALL ICMP',
+ 'ip_protocol': 'icmp',
+ 'from_port': '-1',
+ 'to_port': '-1',
+ },
+ 'ssh': {
+ 'name': 'SSH',
+ 'ip_protocol': 'tcp',
+ 'from_port': '22',
+ 'to_port': '22',
+ },
+ 'smtp': {
+ 'name': 'SMTP',
+ 'ip_protocol': 'tcp',
+ 'from_port': '25',
+ 'to_port': '25',
+ },
+ 'dns': {
+ 'name': 'DNS',
+ 'ip_protocol': 'tcp',
+ 'from_port': '53',
+ 'to_port': '53',
+ },
+ 'http': {
+ 'name': 'HTTP',
+ 'ip_protocol': 'tcp',
+ 'from_port': '80',
+ 'to_port': '80',
+ },
+ 'pop3': {
+ 'name': 'POP3',
+ 'ip_protocol': 'tcp',
+ 'from_port': '110',
+ 'to_port': '110',
+ },
+ 'imap': {
+ 'name': 'IMAP',
+ 'ip_protocol': 'tcp',
+ 'from_port': '143',
+ 'to_port': '143',
+ },
+ 'ldap': {
+ 'name': 'LDAP',
+ 'ip_protocol': 'tcp',
+ 'from_port': '389',
+ 'to_port': '389',
+ },
+ 'https': {
+ 'name': 'HTTPS',
+ 'ip_protocol': 'tcp',
+ 'from_port': '443',
+ 'to_port': '443',
+ },
+ 'smtps': {
+ 'name': 'SMTPS',
+ 'ip_protocol': 'tcp',
+ 'from_port': '465',
+ 'to_port': '465',
+ },
+ 'imaps': {
+ 'name': 'IMAPS',
+ 'ip_protocol': 'tcp',
+ 'from_port': '993',
+ 'to_port': '993',
+ },
+ 'pop3s': {
+ 'name': 'POP3S',
+ 'ip_protocol': 'tcp',
+ 'from_port': '995',
+ 'to_port': '995',
+ },
+ 'ms_sql': {
+ 'name': 'MS SQL',
+ 'ip_protocol': 'tcp',
+ 'from_port': '1433',
+ 'to_port': '1433',
+ },
+ 'mysql': {
+ 'name': 'MYSQL',
+ 'ip_protocol': 'tcp',
+ 'from_port': '3306',
+ 'to_port': '3306',
+ },
+ 'rdp': {
+ 'name': 'RDP',
+ 'ip_protocol': 'tcp',
+ 'from_port': '3389',
+ 'to_port': '3389',
+ },
+}
diff --git a/horizon/files/horizon_settings/_nova_settings.py b/horizon/files/horizon_settings/_nova_settings.py
new file mode 100644
index 0000000..e0b7d78
--- /dev/null
+++ b/horizon/files/horizon_settings/_nova_settings.py
@@ -0,0 +1,41 @@
+{%- from "horizon/map.jinja" import server with context %}
+
+{%- if server.app is defined %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+{%- else %}
+{%- set app = salt['pillar.get']('horizon:server') %}
+{%- endif %}
+
+# Set Console type:
+# valid options would be "AUTO", "VNC" or "SPICE"
+# CONSOLE_TYPE = "AUTO"
+
+# The Xen Hypervisor has the ability to set the mount point for volumes
+# attached to instances (other Hypervisors currently do not). Setting
+# can_set_mount_point to True will add the option to set the mount point
+# from the UI.
+OPENSTACK_HYPERVISOR_FEATURES = {
+ 'can_set_mount_point': False,
+ 'can_set_password': False,
+}
+
+# When launching an instance, the menu of available flavors is
+# sorted by RAM usage, ascending. Provide a callback method here
+# (and/or a flag for reverse sort) for the sorted() method if you'd
+# like a different behaviour. For more info, see
+# http://docs.python.org/2/library/functions.html#sorted
+# CREATE_INSTANCE_FLAVOR_SORT = {
+# 'key': my_awesome_callback_method,
+# 'reverse': False,
+# }
+
+FLAVOR_EXTRA_KEYS = {
+ 'flavor_keys': [
+ ('quota:read_bytes_sec', _('Quota: Read bytes')),
+ ('quota:write_bytes_sec', _('Quota: Write bytes')),
+ ('quota:cpu_quota', _('Quota: CPU')),
+ ('quota:cpu_period', _('Quota: CPU period')),
+ ('quota:inbound_average', _('Quota: Inbound average')),
+ ('quota:outbound_average', _('Quota: Outbound average')),
+ ]
+}
diff --git a/horizon/files/httpd.conf b/horizon/files/httpd.conf
new file mode 100644
index 0000000..990a125
--- /dev/null
+++ b/horizon/files/httpd.conf
@@ -0,0 +1,1009 @@
+#
+# This is the main Apache server configuration file. It contains the
+# configuration directives that give the server its instructions.
+# See <URL:http://httpd.apache.org/docs/2.2/> for detailed information.
+# In particular, see
+# <URL:http://httpd.apache.org/docs/2.2/mod/directives.html>
+# for a discussion of each configuration directive.
+#
+#
+# Do NOT simply read the instructions in here without understanding
+# what they do. They're here only as hints or reminders. If you are unsure
+# consult the online docs. You have been warned.
+#
+# The configuration directives are grouped into three basic sections:
+# 1. Directives that control the operation of the Apache server process as a
+# whole (the 'global environment').
+# 2. Directives that define the parameters of the 'main' or 'default' server,
+# which responds to requests that aren't handled by a virtual host.
+# These directives also provide default values for the settings
+# of all virtual hosts.
+# 3. Settings for virtual hosts, which allow Web requests to be sent to
+# different IP addresses or hostnames and have them handled by the
+# same Apache server process.
+#
+# Configuration and logfile names: If the filenames you specify for many
+# of the server's control files begin with "/" (or "drive:/" for Win32), the
+# server will use that explicit path. If the filenames do *not* begin
+# with "/", the value of ServerRoot is prepended -- so "logs/foo.log"
+# with ServerRoot set to "/etc/httpd" will be interpreted by the
+# server as "/etc/httpd/logs/foo.log".
+#
+
+### Section 1: Global Environment
+#
+# The directives in this section affect the overall operation of Apache,
+# such as the number of concurrent requests it can handle or where it
+# can find its configuration files.
+#
+
+#
+# Don't give away too much information about all the subcomponents
+# we are running. Comment out this line if you don't mind remote sites
+# finding out what major optional modules you are running
+ServerTokens OS
+
+#
+# ServerRoot: The top of the directory tree under which the server's
+# configuration, error, and log files are kept.
+#
+# NOTE! If you intend to place this on an NFS (or otherwise network)
+# mounted filesystem then please read the LockFile documentation
+# (available at <URL:http://httpd.apache.org/docs/2.2/mod/mpm_common.html#lockfile>);
+# you will save yourself a lot of trouble.
+#
+# Do NOT add a slash at the end of the directory path.
+#
+ServerRoot "/etc/httpd"
+
+#
+# PidFile: The file in which the server should record its process
+# identification number when it starts. Note the PIDFILE variable in
+# /etc/sysconfig/httpd must be set appropriately if this location is
+# changed.
+#
+PidFile run/httpd.pid
+
+#
+# Timeout: The number of seconds before receives and sends time out.
+#
+Timeout 60
+
+#
+# KeepAlive: Whether or not to allow persistent connections (more than
+# one request per connection). Set to "Off" to deactivate.
+#
+KeepAlive Off
+
+#
+# MaxKeepAliveRequests: The maximum number of requests to allow
+# during a persistent connection. Set to 0 to allow an unlimited amount.
+# We recommend you leave this number high, for maximum performance.
+#
+MaxKeepAliveRequests 100
+
+#
+# KeepAliveTimeout: Number of seconds to wait for the next request from the
+# same client on the same connection.
+#
+KeepAliveTimeout 15
+
+##
+## Server-Pool Size Regulation (MPM specific)
+##
+
+# prefork MPM
+# StartServers: number of server processes to start
+# MinSpareServers: minimum number of server processes which are kept spare
+# MaxSpareServers: maximum number of server processes which are kept spare
+# ServerLimit: maximum value for MaxClients for the lifetime of the server
+# MaxClients: maximum number of server processes allowed to start
+# MaxRequestsPerChild: maximum number of requests a server process serves
+<IfModule prefork.c>
+StartServers 8
+MinSpareServers 5
+MaxSpareServers 20
+ServerLimit 256
+MaxClients 256
+MaxRequestsPerChild 4000
+</IfModule>
+
+# worker MPM
+# StartServers: initial number of server processes to start
+# MaxClients: maximum number of simultaneous client connections
+# MinSpareThreads: minimum number of worker threads which are kept spare
+# MaxSpareThreads: maximum number of worker threads which are kept spare
+# ThreadsPerChild: constant number of worker threads in each server process
+# MaxRequestsPerChild: maximum number of requests a server process serves
+<IfModule worker.c>
+StartServers 4
+MaxClients 300
+MinSpareThreads 25
+MaxSpareThreads 75
+ThreadsPerChild 25
+MaxRequestsPerChild 0
+</IfModule>
+
+#
+# Listen: Allows you to bind Apache to specific IP addresses and/or
+# ports, in addition to the default. See also the <VirtualHost>
+# directive.
+#
+# Change this to Listen on specific IP addresses as shown below to
+# prevent Apache from glomming onto all bound IP addresses (0.0.0.0)
+#
+#Listen 12.34.56.78:80
+Listen {{ pillar.horizon.server.bind.address }}:{{ pillar.horizon.server.bind.port }}
+
+#
+# Dynamic Shared Object (DSO) Support
+#
+# To be able to use the functionality of a module which was built as a DSO you
+# have to place corresponding `LoadModule' lines at this location so the
+# directives contained in it are actually available _before_ they are used.
+# Statically compiled modules (those listed by `httpd -l') do not need
+# to be loaded here.
+#
+# Example:
+# LoadModule foo_module modules/mod_foo.so
+#
+LoadModule auth_basic_module modules/mod_auth_basic.so
+LoadModule auth_digest_module modules/mod_auth_digest.so
+LoadModule authn_file_module modules/mod_authn_file.so
+LoadModule authn_alias_module modules/mod_authn_alias.so
+LoadModule authn_anon_module modules/mod_authn_anon.so
+LoadModule authn_dbm_module modules/mod_authn_dbm.so
+LoadModule authn_default_module modules/mod_authn_default.so
+LoadModule authz_host_module modules/mod_authz_host.so
+LoadModule authz_user_module modules/mod_authz_user.so
+LoadModule authz_owner_module modules/mod_authz_owner.so
+LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
+LoadModule authz_dbm_module modules/mod_authz_dbm.so
+LoadModule authz_default_module modules/mod_authz_default.so
+LoadModule ldap_module modules/mod_ldap.so
+LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
+LoadModule include_module modules/mod_include.so
+LoadModule log_config_module modules/mod_log_config.so
+LoadModule logio_module modules/mod_logio.so
+LoadModule env_module modules/mod_env.so
+LoadModule ext_filter_module modules/mod_ext_filter.so
+LoadModule mime_magic_module modules/mod_mime_magic.so
+LoadModule expires_module modules/mod_expires.so
+LoadModule deflate_module modules/mod_deflate.so
+LoadModule headers_module modules/mod_headers.so
+LoadModule usertrack_module modules/mod_usertrack.so
+LoadModule setenvif_module modules/mod_setenvif.so
+LoadModule mime_module modules/mod_mime.so
+LoadModule dav_module modules/mod_dav.so
+LoadModule status_module modules/mod_status.so
+LoadModule autoindex_module modules/mod_autoindex.so
+LoadModule info_module modules/mod_info.so
+LoadModule dav_fs_module modules/mod_dav_fs.so
+LoadModule vhost_alias_module modules/mod_vhost_alias.so
+LoadModule negotiation_module modules/mod_negotiation.so
+LoadModule dir_module modules/mod_dir.so
+LoadModule actions_module modules/mod_actions.so
+LoadModule speling_module modules/mod_speling.so
+LoadModule userdir_module modules/mod_userdir.so
+LoadModule alias_module modules/mod_alias.so
+LoadModule substitute_module modules/mod_substitute.so
+LoadModule rewrite_module modules/mod_rewrite.so
+LoadModule proxy_module modules/mod_proxy.so
+LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
+LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
+LoadModule proxy_http_module modules/mod_proxy_http.so
+LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
+LoadModule proxy_connect_module modules/mod_proxy_connect.so
+LoadModule cache_module modules/mod_cache.so
+LoadModule suexec_module modules/mod_suexec.so
+LoadModule disk_cache_module modules/mod_disk_cache.so
+LoadModule cgi_module modules/mod_cgi.so
+LoadModule version_module modules/mod_version.so
+
+#
+# The following modules are not loaded by default:
+#
+#LoadModule asis_module modules/mod_asis.so
+#LoadModule authn_dbd_module modules/mod_authn_dbd.so
+#LoadModule cern_meta_module modules/mod_cern_meta.so
+#LoadModule cgid_module modules/mod_cgid.so
+#LoadModule dbd_module modules/mod_dbd.so
+#LoadModule dumpio_module modules/mod_dumpio.so
+#LoadModule filter_module modules/mod_filter.so
+#LoadModule ident_module modules/mod_ident.so
+#LoadModule log_forensic_module modules/mod_log_forensic.so
+#LoadModule unique_id_module modules/mod_unique_id.so
+#
+
+#
+# Load config files from the config directory "/etc/httpd/conf.d".
+#
+Include conf.d/*.conf
+
+#
+# ExtendedStatus controls whether Apache will generate "full" status
+# information (ExtendedStatus On) or just basic information (ExtendedStatus
+# Off) when the "server-status" handler is called. The default is Off.
+#
+#ExtendedStatus On
+
+#
+# If you wish httpd to run as a different user or group, you must run
+# httpd as root initially and it will switch.
+#
+# User/Group: The name (or #number) of the user/group to run httpd as.
+# . On SCO (ODT 3) use "User nouser" and "Group nogroup".
+# . On HPUX you may not be able to use shared memory as nobody, and the
+# suggested workaround is to create a user www and use that user.
+# NOTE that some kernels refuse to setgid(Group) or semctl(IPC_SET)
+# when the value of (unsigned)Group is above 60000;
+# don't use Group #-1 on these systems!
+#
+User apache
+Group apache
+
+### Section 2: 'Main' server configuration
+#
+# The directives in this section set up the values used by the 'main'
+# server, which responds to any requests that aren't handled by a
+# <VirtualHost> definition. These values also provide defaults for
+# any <VirtualHost> containers you may define later in the file.
+#
+# All of these directives may appear inside <VirtualHost> containers,
+# in which case these default settings will be overridden for the
+# virtual host being defined.
+#
+
+#
+# ServerAdmin: Your address, where problems with the server should be
+# e-mailed. This address appears on some server-generated pages, such
+# as error documents. e.g. admin@your-domain.com
+#
+ServerAdmin root@localhost
+
+#
+# ServerName gives the name and port that the server uses to identify itself.
+# This can often be determined automatically, but we recommend you specify
+# it explicitly to prevent problems during startup.
+#
+# If this is not set to valid DNS name for your host, server-generated
+# redirections will not work. See also the UseCanonicalName directive.
+#
+# If your host doesn't have a registered DNS name, enter its IP address here.
+# You will have to access it by its address anyway, and this will make
+# redirections work in a sensible way.
+#
+#ServerName www.example.com:80
+
+#
+# UseCanonicalName: Determines how Apache constructs self-referencing
+# URLs and the SERVER_NAME and SERVER_PORT variables.
+# When set "Off", Apache will use the Hostname and Port supplied
+# by the client. When set "On", Apache will use the value of the
+# ServerName directive.
+#
+UseCanonicalName Off
+
+#
+# DocumentRoot: The directory out of which you will serve your
+# documents. By default, all requests are taken from this directory, but
+# symbolic links and aliases may be used to point to other locations.
+#
+DocumentRoot "/var/www/html"
+
+#
+# Each directory to which Apache has access can be configured with respect
+# to which services and features are allowed and/or disabled in that
+# directory (and its subdirectories).
+#
+# First, we configure the "default" to be a very restrictive set of
+# features.
+#
+<Directory />
+ Options FollowSymLinks
+ AllowOverride None
+</Directory>
+
+#
+# Note that from this point forward you must specifically allow
+# particular features to be enabled - so if something's not working as
+# you might expect, make sure that you have specifically enabled it
+# below.
+#
+
+#
+# This should be changed to whatever you set DocumentRoot to.
+#
+<Directory "/var/www/html">
+
+#
+# Possible values for the Options directive are "None", "All",
+# or any combination of:
+# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
+#
+# Note that "MultiViews" must be named *explicitly* --- "Options All"
+# doesn't give it to you.
+#
+# The Options directive is both complicated and important. Please see
+# http://httpd.apache.org/docs/2.2/mod/core.html#options
+# for more information.
+#
+ Options Indexes FollowSymLinks
+
+#
+# AllowOverride controls what directives may be placed in .htaccess files.
+# It can be "All", "None", or any combination of the keywords:
+# Options FileInfo AuthConfig Limit
+#
+ AllowOverride None
+
+#
+# Controls who can get stuff from this server.
+#
+ Order allow,deny
+ Allow from all
+
+</Directory>
+
+#
+# UserDir: The name of the directory that is appended onto a user's home
+# directory if a ~user request is received.
+#
+# The path to the end user account 'public_html' directory must be
+# accessible to the webserver userid. This usually means that ~userid
+# must have permissions of 711, ~userid/public_html must have permissions
+# of 755, and documents contained therein must be world-readable.
+# Otherwise, the client will only receive a "403 Forbidden" message.
+#
+# See also: http://httpd.apache.org/docs/misc/FAQ.html#forbidden
+#
+<IfModule mod_userdir.c>
+ #
+ # UserDir is disabled by default since it can confirm the presence
+ # of a username on the system (depending on home directory
+ # permissions).
+ #
+ UserDir disabled
+
+ #
+ # To enable requests to /~user/ to serve the user's public_html
+ # directory, remove the "UserDir disabled" line above, and uncomment
+ # the following line instead:
+ #
+ #UserDir public_html
+
+</IfModule>
+
+#
+# Control access to UserDir directories. The following is an example
+# for a site where these directories are restricted to read-only.
+#
+#<Directory /home/*/public_html>
+# AllowOverride FileInfo AuthConfig Limit
+# Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
+# <Limit GET POST OPTIONS>
+# Order allow,deny
+# Allow from all
+# </Limit>
+# <LimitExcept GET POST OPTIONS>
+# Order deny,allow
+# Deny from all
+# </LimitExcept>
+#</Directory>
+
+#
+# DirectoryIndex: sets the file that Apache will serve if a directory
+# is requested.
+#
+# The index.html.var file (a type-map) is used to deliver content-
+# negotiated documents. The MultiViews Option can be used for the
+# same purpose, but it is much slower.
+#
+DirectoryIndex index.html index.html.var
+
+#
+# AccessFileName: The name of the file to look for in each directory
+# for additional configuration directives. See also the AllowOverride
+# directive.
+#
+AccessFileName .htaccess
+
+#
+# The following lines prevent .htaccess and .htpasswd files from being
+# viewed by Web clients.
+#
+<Files ~ "^\.ht">
+ Order allow,deny
+ Deny from all
+ Satisfy All
+</Files>
+
+#
+# TypesConfig describes where the mime.types file (or equivalent) is
+# to be found.
+#
+TypesConfig /etc/mime.types
+
+#
+# DefaultType is the default MIME type the server will use for a document
+# if it cannot otherwise determine one, such as from filename extensions.
+# If your server contains mostly text or HTML documents, "text/plain" is
+# a good value. If most of your content is binary, such as applications
+# or images, you may want to use "application/octet-stream" instead to
+# keep browsers from trying to display binary files as though they are
+# text.
+#
+DefaultType text/plain
+
+#
+# The mod_mime_magic module allows the server to use various hints from the
+# contents of the file itself to determine its type. The MIMEMagicFile
+# directive tells the module where the hint definitions are located.
+#
+<IfModule mod_mime_magic.c>
+# MIMEMagicFile /usr/share/magic.mime
+ MIMEMagicFile conf/magic
+</IfModule>
+
+#
+# HostnameLookups: Log the names of clients or just their IP addresses
+# e.g., www.apache.org (on) or 204.62.129.132 (off).
+# The default is off because it'd be overall better for the net if people
+# had to knowingly turn this feature on, since enabling it means that
+# each client request will result in AT LEAST one lookup request to the
+# nameserver.
+#
+HostnameLookups Off
+
+#
+# EnableMMAP: Control whether memory-mapping is used to deliver
+# files (assuming that the underlying OS supports it).
+# The default is on; turn this off if you serve from NFS-mounted
+# filesystems. On some systems, turning it off (regardless of
+# filesystem) can improve performance; for details, please see
+# http://httpd.apache.org/docs/2.2/mod/core.html#enablemmap
+#
+#EnableMMAP off
+
+#
+# EnableSendfile: Control whether the sendfile kernel support is
+# used to deliver files (assuming that the OS supports it).
+# The default is on; turn this off if you serve from NFS-mounted
+# filesystems. Please see
+# http://httpd.apache.org/docs/2.2/mod/core.html#enablesendfile
+#
+#EnableSendfile off
+
+#
+# ErrorLog: The location of the error log file.
+# If you do not specify an ErrorLog directive within a <VirtualHost>
+# container, error messages relating to that virtual host will be
+# logged here. If you *do* define an error logfile for a <VirtualHost>
+# container, that host's errors will be logged there and not here.
+#
+ErrorLog logs/error_log
+
+#
+# LogLevel: Control the number of messages logged to the error_log.
+# Possible values include: debug, info, notice, warn, error, crit,
+# alert, emerg.
+#
+LogLevel warn
+
+#
+# The following directives define some format nicknames for use with
+# a CustomLog directive (see below).
+#
+LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%h %l %u %t \"%r\" %>s %b" common
+LogFormat "%{Referer}i -> %U" referer
+LogFormat "%{User-agent}i" agent
+
+# "combinedio" includes actual counts of actual bytes received (%I) and sent (%O); this
+# requires the mod_logio module to be loaded.
+#LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
+
+#
+# The location and format of the access logfile (Common Logfile Format).
+# If you do not define any access logfiles within a <VirtualHost>
+# container, they will be logged here. Contrariwise, if you *do*
+# define per-<VirtualHost> access logfiles, transactions will be
+# logged therein and *not* in this file.
+#
+#CustomLog logs/access_log common
+
+#
+# If you would like to have separate agent and referer logfiles, uncomment
+# the following directives.
+#
+#CustomLog logs/referer_log referer
+#CustomLog logs/agent_log agent
+
+#
+# For a single logfile with access, agent, and referer information
+# (Combined Logfile Format), use the following directive:
+#
+CustomLog logs/access_log combined
+
+#
+# Optionally add a line containing the server version and virtual host
+# name to server-generated pages (internal error documents, FTP directory
+# listings, mod_status and mod_info output etc., but not CGI generated
+# documents or custom error documents).
+# Set to "EMail" to also include a mailto: link to the ServerAdmin.
+# Set to one of: On | Off | EMail
+#
+ServerSignature On
+
+#
+# Aliases: Add here as many aliases as you need (with no limit). The format is
+# Alias fakename realname
+#
+# Note that if you include a trailing / on fakename then the server will
+# require it to be present in the URL. So "/icons" isn't aliased in this
+# example, only "/icons/". If the fakename is slash-terminated, then the
+# realname must also be slash terminated, and if the fakename omits the
+# trailing slash, the realname must also omit it.
+#
+# We include the /icons/ alias for FancyIndexed directory listings. If you
+# do not use FancyIndexing, you may comment this out.
+#
+Alias /icons/ "/var/www/icons/"
+
+<Directory "/var/www/icons">
+ Options Indexes MultiViews FollowSymLinks
+ AllowOverride None
+ Order allow,deny
+ Allow from all
+</Directory>
+
+#
+# WebDAV module configuration section.
+#
+<IfModule mod_dav_fs.c>
+ # Location of the WebDAV lock database.
+ DAVLockDB /var/lib/dav/lockdb
+</IfModule>
+
+#
+# ScriptAlias: This controls which directories contain server scripts.
+# ScriptAliases are essentially the same as Aliases, except that
+# documents in the realname directory are treated as applications and
+# run by the server when requested rather than as documents sent to the client.
+# The same rules about trailing "/" apply to ScriptAlias directives as to
+# Alias.
+#
+ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
+
+#
+# "/var/www/cgi-bin" should be changed to whatever your ScriptAliased
+# CGI directory exists, if you have that configured.
+#
+<Directory "/var/www/cgi-bin">
+ AllowOverride None
+ Options None
+ Order allow,deny
+ Allow from all
+</Directory>
+
+#
+# Redirect allows you to tell clients about documents which used to exist in
+# your server's namespace, but do not anymore. This allows you to tell the
+# clients where to look for the relocated document.
+# Example:
+# Redirect permanent /foo http://www.example.com/bar
+
+#
+# Directives controlling the display of server-generated directory listings.
+#
+
+#
+# IndexOptions: Controls the appearance of server-generated directory
+# listings.
+#
+IndexOptions FancyIndexing VersionSort NameWidth=* HTMLTable Charset=UTF-8
+
+#
+# AddIcon* directives tell the server which icon to show for different
+# files or filename extensions. These are only displayed for
+# FancyIndexed directories.
+#
+AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
+
+AddIconByType (TXT,/icons/text.gif) text/*
+AddIconByType (IMG,/icons/image2.gif) image/*
+AddIconByType (SND,/icons/sound2.gif) audio/*
+AddIconByType (VID,/icons/movie.gif) video/*
+
+AddIcon /icons/binary.gif .bin .exe
+AddIcon /icons/binhex.gif .hqx
+AddIcon /icons/tar.gif .tar
+AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
+AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
+AddIcon /icons/a.gif .ps .ai .eps
+AddIcon /icons/layout.gif .html .shtml .htm .pdf
+AddIcon /icons/text.gif .txt
+AddIcon /icons/c.gif .c
+AddIcon /icons/p.gif .pl .py
+AddIcon /icons/f.gif .for
+AddIcon /icons/dvi.gif .dvi
+AddIcon /icons/uuencoded.gif .uu
+AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
+AddIcon /icons/tex.gif .tex
+AddIcon /icons/bomb.gif core
+
+AddIcon /icons/back.gif ..
+AddIcon /icons/hand.right.gif README
+AddIcon /icons/folder.gif ^^DIRECTORY^^
+AddIcon /icons/blank.gif ^^BLANKICON^^
+
+#
+# DefaultIcon is which icon to show for files which do not have an icon
+# explicitly set.
+#
+DefaultIcon /icons/unknown.gif
+
+#
+# AddDescription allows you to place a short description after a file in
+# server-generated indexes. These are only displayed for FancyIndexed
+# directories.
+# Format: AddDescription "description" filename
+#
+#AddDescription "GZIP compressed document" .gz
+#AddDescription "tar archive" .tar
+#AddDescription "GZIP compressed tar archive" .tgz
+
+#
+# ReadmeName is the name of the README file the server will look for by
+# default, and append to directory listings.
+#
+# HeaderName is the name of a file which should be prepended to
+# directory indexes.
+ReadmeName README.html
+HeaderName HEADER.html
+
+#
+# IndexIgnore is a set of filenames which directory indexing should ignore
+# and not include in the listing. Shell-style wildcarding is permitted.
+#
+IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t
+
+#
+# DefaultLanguage and AddLanguage allows you to specify the language of
+# a document. You can then use content negotiation to give a browser a
+# file in a language the user can understand.
+#
+# Specify a default language. This means that all data
+# going out without a specific language tag (see below) will
+# be marked with this one. You probably do NOT want to set
+# this unless you are sure it is correct for all cases.
+#
+# * It is generally better to not mark a page as
+# * being a certain language than marking it with the wrong
+# * language!
+#
+# DefaultLanguage nl
+#
+# Note 1: The suffix does not have to be the same as the language
+# keyword --- those with documents in Polish (whose net-standard
+# language code is pl) may wish to use "AddLanguage pl .po" to
+# avoid the ambiguity with the common suffix for perl scripts.
+#
+# Note 2: The example entries below illustrate that in some cases
+# the two character 'Language' abbreviation is not identical to
+# the two character 'Country' code for its country,
+# E.g. 'Danmark/dk' versus 'Danish/da'.
+#
+# Note 3: In the case of 'ltz' we violate the RFC by using a three char
+# specifier. There is 'work in progress' to fix this and get
+# the reference data for rfc1766 cleaned up.
+#
+# Catalan (ca) - Croatian (hr) - Czech (cs) - Danish (da) - Dutch (nl)
+# English (en) - Esperanto (eo) - Estonian (et) - French (fr) - German (de)
+# Greek-Modern (el) - Hebrew (he) - Italian (it) - Japanese (ja)
+# Korean (ko) - Luxembourgeois* (ltz) - Norwegian Nynorsk (nn)
+# Norwegian (no) - Polish (pl) - Portugese (pt)
+# Brazilian Portuguese (pt-BR) - Russian (ru) - Swedish (sv)
+# Simplified Chinese (zh-CN) - Spanish (es) - Traditional Chinese (zh-TW)
+#
+AddLanguage ca .ca
+AddLanguage cs .cz .cs
+AddLanguage da .dk
+AddLanguage de .de
+AddLanguage el .el
+AddLanguage en .en
+AddLanguage eo .eo
+AddLanguage es .es
+AddLanguage et .et
+AddLanguage fr .fr
+AddLanguage he .he
+AddLanguage hr .hr
+AddLanguage it .it
+AddLanguage ja .ja
+AddLanguage ko .ko
+AddLanguage ltz .ltz
+AddLanguage nl .nl
+AddLanguage nn .nn
+AddLanguage no .no
+AddLanguage pl .po
+AddLanguage pt .pt
+AddLanguage pt-BR .pt-br
+AddLanguage ru .ru
+AddLanguage sv .sv
+AddLanguage zh-CN .zh-cn
+AddLanguage zh-TW .zh-tw
+
+#
+# LanguagePriority allows you to give precedence to some languages
+# in case of a tie during content negotiation.
+#
+# Just list the languages in decreasing order of preference. We have
+# more or less alphabetized them here. You probably want to change this.
+#
+LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW
+
+#
+# ForceLanguagePriority allows you to serve a result page rather than
+# MULTIPLE CHOICES (Prefer) [in case of a tie] or NOT ACCEPTABLE (Fallback)
+# [in case no accepted languages matched the available variants]
+#
+ForceLanguagePriority Prefer Fallback
+
+#
+# Specify a default charset for all content served; this enables
+# interpretation of all content as UTF-8 by default. To use the
+# default browser choice (ISO-8859-1), or to allow the META tags
+# in HTML content to override this choice, comment out this
+# directive:
+#
+AddDefaultCharset UTF-8
+
+#
+# AddType allows you to add to or override the MIME configuration
+# file mime.types for specific file types.
+#
+#AddType application/x-tar .tgz
+
+#
+# AddEncoding allows you to have certain browsers uncompress
+# information on the fly. Note: Not all browsers support this.
+# Despite the name similarity, the following Add* directives have nothing
+# to do with the FancyIndexing customization directives above.
+#
+#AddEncoding x-compress .Z
+#AddEncoding x-gzip .gz .tgz
+
+# If the AddEncoding directives above are commented-out, then you
+# probably should define those extensions to indicate media types:
+#
+AddType application/x-compress .Z
+AddType application/x-gzip .gz .tgz
+
+#
+# MIME-types for downloading Certificates and CRLs
+#
+AddType application/x-x509-ca-cert .crt
+AddType application/x-pkcs7-crl .crl
+
+#
+# AddHandler allows you to map certain file extensions to "handlers":
+# actions unrelated to filetype. These can be either built into the server
+# or added with the Action directive (see below)
+#
+# To use CGI scripts outside of ScriptAliased directories:
+# (You will also need to add "ExecCGI" to the "Options" directive.)
+#
+#AddHandler cgi-script .cgi
+
+#
+# For files that include their own HTTP headers:
+#
+#AddHandler send-as-is asis
+
+#
+# For type maps (negotiated resources):
+# (This is enabled by default to allow the Apache "It Worked" page
+# to be distributed in multiple languages.)
+#
+AddHandler type-map var
+
+#
+# Filters allow you to process content before it is sent to the client.
+#
+# To parse .shtml files for server-side includes (SSI):
+# (You will also need to add "Includes" to the "Options" directive.)
+#
+AddType text/html .shtml
+AddOutputFilter INCLUDES .shtml
+
+#
+# Action lets you define media types that will execute a script whenever
+# a matching file is called. This eliminates the need for repeated URL
+# pathnames for oft-used CGI file processors.
+# Format: Action media/type /cgi-script/location
+# Format: Action handler-name /cgi-script/location
+#
+
+#
+# Customizable error responses come in three flavors:
+# 1) plain text 2) local redirects 3) external redirects
+#
+# Some examples:
+#ErrorDocument 500 "The server made a boo boo."
+#ErrorDocument 404 /missing.html
+#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
+#ErrorDocument 402 http://www.example.com/subscription_info.html
+#
+
+#
+# Putting this all together, we can internationalize error responses.
+#
+# We use Alias to redirect any /error/HTTP_<error>.html.var response to
+# our collection of by-error message multi-language collections. We use
+# includes to substitute the appropriate text.
+#
+# You can modify the messages' appearance without changing any of the
+# default HTTP_<error>.html.var files by adding the line:
+#
+# Alias /error/include/ "/your/include/path/"
+#
+# which allows you to create your own set of files by starting with the
+# /var/www/error/include/ files and
+# copying them to /your/include/path/, even on a per-VirtualHost basis.
+#
+
+Alias /error/ "/var/www/error/"
+
+<IfModule mod_negotiation.c>
+<IfModule mod_include.c>
+ <Directory "/var/www/error">
+ AllowOverride None
+ Options IncludesNoExec
+ AddOutputFilter Includes html
+ AddHandler type-map var
+ Order allow,deny
+ Allow from all
+ LanguagePriority en es de fr
+ ForceLanguagePriority Prefer Fallback
+ </Directory>
+
+# ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var
+# ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var
+# ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var
+# ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var
+# ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var
+# ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var
+# ErrorDocument 410 /error/HTTP_GONE.html.var
+# ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var
+# ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var
+# ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var
+# ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var
+# ErrorDocument 415 /error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var
+# ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var
+# ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var
+# ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var
+# ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var
+# ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var
+
+</IfModule>
+</IfModule>
+
+#
+# The following directives modify normal HTTP response behavior to
+# handle known problems with browser implementations.
+#
+BrowserMatch "Mozilla/2" nokeepalive
+BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
+BrowserMatch "RealPlayer 4\.0" force-response-1.0
+BrowserMatch "Java/1\.0" force-response-1.0
+BrowserMatch "JDK/1\.0" force-response-1.0
+
+#
+# The following directive disables redirects on non-GET requests for
+# a directory that does not include the trailing slash. This fixes a
+# problem with Microsoft WebFolders which does not appropriately handle
+# redirects for folders with DAV methods.
+# Same deal with Apple's DAV filesystem and Gnome VFS support for DAV.
+#
+BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
+BrowserMatch "MS FrontPage" redirect-carefully
+BrowserMatch "^WebDrive" redirect-carefully
+BrowserMatch "^WebDAVFS/1.[0123]" redirect-carefully
+BrowserMatch "^gnome-vfs/1.0" redirect-carefully
+BrowserMatch "^XML Spy" redirect-carefully
+BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
+
+#
+# Allow server status reports generated by mod_status,
+# with the URL of http://servername/server-status
+# Change the ".example.com" to match your domain to enable.
+#
+#<Location /server-status>
+# SetHandler server-status
+# Order deny,allow
+# Deny from all
+# Allow from .example.com
+#</Location>
+
+#
+# Allow remote server configuration reports, with the URL of
+# http://servername/server-info (requires that mod_info.c be loaded).
+# Change the ".example.com" to match your domain to enable.
+#
+#<Location /server-info>
+# SetHandler server-info
+# Order deny,allow
+# Deny from all
+# Allow from .example.com
+#</Location>
+
+#
+# Proxy Server directives. Uncomment the following lines to
+# enable the proxy server:
+#
+#<IfModule mod_proxy.c>
+#ProxyRequests On
+#
+#<Proxy *>
+# Order deny,allow
+# Deny from all
+# Allow from .example.com
+#</Proxy>
+
+#
+# Enable/disable the handling of HTTP/1.1 "Via:" headers.
+# ("Full" adds the server version; "Block" removes all outgoing Via: headers)
+# Set to one of: Off | On | Full | Block
+#
+#ProxyVia On
+
+#
+# To enable a cache of proxied content, uncomment the following lines.
+# See http://httpd.apache.org/docs/2.2/mod/mod_cache.html for more details.
+#
+#<IfModule mod_disk_cache.c>
+# CacheEnable disk /
+# CacheRoot "/var/cache/mod_proxy"
+#</IfModule>
+#
+
+#</IfModule>
+# End of proxy directives.
+
+### Section 3: Virtual Hosts
+#
+# VirtualHost: If you want to maintain multiple domains/hostnames on your
+# machine you can setup VirtualHost containers for them. Most configurations
+# use only name-based virtual hosts so the server doesn't need to worry about
+# IP addresses. This is indicated by the asterisks in the directives below.
+#
+# Please see the documentation at
+# <URL:http://httpd.apache.org/docs/2.2/vhosts/>
+# for further details before you try to setup virtual hosts.
+#
+# You may use the command line option '-S' to verify your virtual host
+# configuration.
+
+#
+# Use name-based virtual hosting.
+#
+#NameVirtualHost *:80
+#
+# NOTE: NameVirtualHost cannot be used without a port specifier
+# (e.g. :80) if mod_ssl is being used, due to the nature of the
+# SSL protocol.
+#
+
+#
+# VirtualHost example:
+# Almost any Apache directive may go into a VirtualHost container.
+# The first VirtualHost section is used for requests without a known
+# server name.
+#
+#<VirtualHost *:80>
+# ServerAdmin webmaster@dummy-host.example.com
+# DocumentRoot /www/docs/dummy-host.example.com
+# ServerName dummy-host.example.com
+# ErrorLog logs/dummy-host.example.com-error_log
+# CustomLog logs/dummy-host.example.com-access_log common
+#</VirtualHost>
diff --git a/horizon/files/local_settings/csb_settings.py b/horizon/files/local_settings/csb_settings.py
new file mode 100644
index 0000000..9f7110f
--- /dev/null
+++ b/horizon/files/local_settings/csb_settings.py
@@ -0,0 +1,57 @@
+import os
+from django.utils.translation import ugettext_lazy as _
+from openstack_dashboard import exceptions
+
+{%- from "horizon/map.jinja" import server with context %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+
+HORIZON_CONFIG = {
+ 'dashboards': ({% if app.plugin is defined %}{% for plugin_name, plugin in app.plugin.iteritems() %}{% if plugin.get('dashboard', False) %}'{{ plugin_name }}', {% endif %}{% endfor %}{% endif %}'admin', 'settings'),
+ 'default_dashboard': '{{ app.get('default_dashboard', 'project') }}',
+ 'user_home': '{{ app.get('user_home', 'openstack_dashboard.views.get_user_home') }}',
+ 'ajax_queue_limit': 10,
+ 'auto_fade_alerts': {
+ 'delay': 3000,
+ 'fade_duration': 1500,
+ 'types': ['alert-success', 'alert-info']
+ },
+ 'help_url': "{{ app.get('help_url', 'http://docs.openstack.org') }}",
+ 'exceptions': {'recoverable': exceptions.RECOVERABLE,
+ 'not_found': exceptions.NOT_FOUND,
+ 'unauthorized': exceptions.UNAUTHORIZED},
+}
+
+INSTALLED_APPS = (
+ {%- for plugin_name, plugin in app.plugin.iteritems() %}
+ '{{ plugin.app }}',
+ {%- endfor %}
+ 'csb_dashboard',
+ 'csb_dashboard.dashboards.service',
+ 'csb_dashboard.dashboards.admin',
+ 'csb_dashboard.dashboards.api_office365',
+ 'csb_dashboard.dashboards.heat_stack',
+ 'csb_dashboard.dashboards.salt_cloud',
+ 'csb_dashboard.dashboards.salt_system',
+ 'theme',
+ 'horizon_overrides',
+ 'django.contrib.contenttypes',
+ 'django.contrib.auth',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'django.contrib.humanize',
+ 'compressor',
+ 'horizon',
+ 'csbclient',
+ 'csb_auth',
+ 'markitup',
+ 'image_proxy',
+ {%- if app.logging is defined %}
+ 'raven.contrib.django.raven_compat',
+ {%- endif %}
+)
+
+MEDIA_ROOT = '/srv/horizon/sites/{{ app_name }}/media/'
+STATIC_ROOT = '/srv/horizon/sites/{{ app_name }}/static/'
+
+{% include "horizon/files/horizon_settings/_local_settings.py" %}
\ No newline at end of file
diff --git a/horizon/files/local_settings/helpdesk_settings.py b/horizon/files/local_settings/helpdesk_settings.py
new file mode 100644
index 0000000..432c0d4
--- /dev/null
+++ b/horizon/files/local_settings/helpdesk_settings.py
@@ -0,0 +1,75 @@
+import os
+from django.utils.translation import ugettext_lazy as _
+from openstack_dashboard import exceptions
+
+{%- from "horizon/map.jinja" import server with context %}
+
+{%- if server.app is defined %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+{%- else %}
+{%- set app = salt['pillar.get']('horizon:server') %}
+{%- endif %}
+
+# OpenStack Dashboard configuration.
+HORIZON_CONFIG = {
+ 'dashboards': ({% if app.plugin is defined %}{% for plugin_name, plugin in app.plugin.iteritems() %}{% if plugin.get('dashboard', False) %}'{{ plugin_name }}', {% endif %}{% endfor %}{% endif %}'admin', 'settings'),
+ 'default_dashboard': '{{ app.get('default_dashboard', 'project') }}',
+ 'user_home': 'helpdesk_dashboard.views.splash',
+ 'ajax_queue_limit': 10,
+ 'auto_fade_alerts': {
+ 'delay': 3000,
+ 'fade_duration': 1500,
+ 'types': ['alert-success', 'alert-info']
+ },
+ 'help_url': "{{ app.get('help_url', 'http://docs.openstack.org') }}",
+ 'exceptions': {'recoverable': exceptions.RECOVERABLE,
+ 'not_found': exceptions.NOT_FOUND,
+ 'unauthorized': exceptions.UNAUTHORIZED},
+ 'password_autocomplete': 'on'
+}
+
+SESSION_TIMEOUT = 3600 * 24
+
+{%- if app.theme is defined or app.plugin.horizon_theme is defined %}
+{%- if app.theme is defined %}
+CUSTOM_THEME_PATH = 'dashboards/theme/static/themes/{{ app.theme }}'
+{%- elif app.plugin.horizon_theme.theme_name is defined %}
+# Enable custom theme if it is present.
+try:
+ from openstack_dashboard.enabled._99_horizon_theme import CUSTOM_THEME_PATH
+except ImportError:
+ pass
+{%- endif %}
+{%- endif %}
+
+INSTALLED_APPS = (
+ 'openstack_dashboard',
+ 'django.contrib.contenttypes',
+ 'django.contrib.auth',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'django.contrib.humanize',
+ 'compressor',
+ 'horizon',
+ {%- if app.logging is defined %}
+ 'raven.contrib.django.raven_compat',
+ {%- endif %}
+)
+
+REDACTOR_OPTIONS = {'lang': 'en', 'buttonsHide': ['file', 'image']}
+REDACTOR_UPLOAD = 'uploads/'
+
+ROOT_URLCONF = 'helpdesk_dashboard.url_overrides'
+
+{% include "horizon/files/horizon_settings/_keystone_settings.py" %}
+{% include "horizon/files/horizon_settings/_local_settings.py" %}
+
+AUTHENTICATION_BACKENDS = ('helpdesk_auth.backend.HelpdeskBackend',)
+
+AUTHENTICATION_URLS = ['helpdesk_auth.urls']
+
+API_RESULT_PAGE_SIZE = 25
+
+{% include "horizon/files/horizon_settings/_horizon_settings.py" %}
+
diff --git a/horizon/files/local_settings/juno_settings.py b/horizon/files/local_settings/juno_settings.py
new file mode 100644
index 0000000..67c1657
--- /dev/null
+++ b/horizon/files/local_settings/juno_settings.py
@@ -0,0 +1,77 @@
+import os
+from django.utils.translation import ugettext_lazy as _
+from openstack_dashboard import exceptions
+
+{%- from "horizon/map.jinja" import server with context %}
+
+{%- if server.app is defined %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+{%- else %}
+{%- set app = salt['pillar.get']('horizon:server') %}
+{%- endif %}
+
+HORIZON_CONFIG = {
+ 'dashboards': ({% if app.plugin is defined %}{% for plugin_name, plugin in app.plugin.iteritems() %}{% if plugin.get('dashboard', False) %}'{{ plugin_name }}', {% endif %}{% endfor %}{% endif %}'admin', 'settings'),
+ 'default_dashboard': '{{ app.get('default_dashboard', 'project') }}',
+ 'user_home': '{{ app.get('user_home', 'openstack_dashboard.views.get_user_home') }}',
+ 'ajax_queue_limit': 10,
+ 'auto_fade_alerts': {
+ 'delay': 3000,
+ 'fade_duration': 1500,
+ 'types': ['alert-success', 'alert-info']
+ },
+ 'help_url': "{{ app.get('help_url', 'http://docs.openstack.org') }}",
+ 'exceptions': {'recoverable': exceptions.RECOVERABLE,
+ 'not_found': exceptions.NOT_FOUND,
+ 'unauthorized': exceptions.UNAUTHORIZED},
+}
+
+TEMPLATE_LOADERS = (
+ 'django.template.loaders.app_directories.Loader',
+ 'django.template.loaders.filesystem.Loader',
+ 'horizon.loaders.TemplateLoader'
+)
+
+INSTALLED_APPS = (
+ {%- for plugin_name, plugin in app.plugin.iteritems() %}
+ '{{ plugin.app }}',
+ {%- if plugin_name == 'robotice_dashboard' %}
+ 'robotice_dashboard.dashboards.location',
+ 'robotice_dashboard.dashboards.admin',
+ 'robotice_auth',
+ {%- endif %}
+ {%- if plugin_name == 'helpdesk' %}
+ 'redactor',
+ {%- endif %}
+ {%- endfor %}
+ 'openstack_dashboard',
+ 'django.contrib.contenttypes',
+ 'django.contrib.auth',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'django.contrib.humanize',
+ 'compressor',
+ 'horizon',
+ {%- if app.version == 'csb' %}
+ 'markitup',
+ 'image_proxy',
+ 'csb_dashboard.dashboards.service',
+ 'csb_dashboard.dashboards.admin',
+ 'csb_dashboard.dashboards.api_office365',
+ 'csb_dashboard.dashboards.heat_stack',
+ 'csb_dashboard.dashboards.salt_cloud',
+ 'csb_dashboard.dashboards.salt_system',
+ {%- endif %}
+ 'openstack_auth',
+ {%- if app.logging is defined %}
+ 'raven.contrib.django.raven_compat',
+ {%- endif %}
+)
+
+{% include "horizon/files/horizon_settings/_local_settings.py" %}
+{% include "horizon/files/horizon_settings/_horizon_settings.py" %}
+{% include "horizon/files/horizon_settings/_keystone_settings.py" %}
+{% include "horizon/files/horizon_settings/_nova_settings.py" %}
+{% include "horizon/files/horizon_settings/_glance_settings.py" %}
+{% include "horizon/files/horizon_settings/_neutron_settings.py" %}
diff --git a/horizon/files/local_settings/kilo_settings.py b/horizon/files/local_settings/kilo_settings.py
new file mode 100644
index 0000000..3c59278
--- /dev/null
+++ b/horizon/files/local_settings/kilo_settings.py
@@ -0,0 +1,59 @@
+import os
+from django.utils.translation import ugettext_lazy as _
+from openstack_dashboard import exceptions
+
+{%- from "horizon/map.jinja" import server with context %}
+
+{%- if server.app is defined %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+{%- else %}
+{%- set app = salt['pillar.get']('horizon:server') %}
+{%- endif %}
+
+HORIZON_CONFIG = {
+ 'user_home': 'openstack_dashboard.views.get_user_home',
+ 'ajax_queue_limit': 10,
+ 'auto_fade_alerts': {
+ 'delay': 3000,
+ 'fade_duration': 1500,
+ 'types': ['alert-success', 'alert-info']
+ },
+ 'help_url': "http://docs.openstack.org",
+ 'exceptions': {'recoverable': exceptions.RECOVERABLE,
+ 'not_found': exceptions.NOT_FOUND,
+ 'unauthorized': exceptions.UNAUTHORIZED},
+ 'modal_backdrop': 'static',
+ 'angular_modules': [],
+ 'js_files': [],
+ 'js_spec_files': [],
+ 'password_autocomplete': 'on'
+}
+
+{%- if app.theme is defined %}
+CUSTOM_THEME_PATH = 'static/themes/{{ app.theme }}'
+{%- elif app.plugin.horizon_theme.theme_name is defined %}
+CUSTOM_THEME_PATH = 'static/themes/{{ app.plugin.horizon_theme.theme_name }}'
+{%- endif %}
+
+INSTALLED_APPS = (
+ 'openstack_dashboard',
+ 'django.contrib.contenttypes',
+ 'django.contrib.auth',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'django.contrib.humanize',
+ 'compressor',
+ 'horizon',
+ 'openstack_auth',
+ {%- if app.logging is defined %}
+ 'raven.contrib.django.raven_compat',
+ {%- endif %}
+)
+
+{% include "horizon/files/horizon_settings/_local_settings.py" %}
+{% include "horizon/files/horizon_settings/_horizon_settings.py" %}
+{% include "horizon/files/horizon_settings/_keystone_settings.py" %}
+{% include "horizon/files/horizon_settings/_nova_settings.py" %}
+{% include "horizon/files/horizon_settings/_glance_settings.py" %}
+{% include "horizon/files/horizon_settings/_neutron_settings.py" %}
diff --git a/horizon/files/local_settings/liberty_settings.py b/horizon/files/local_settings/liberty_settings.py
new file mode 100644
index 0000000..47e3587
--- /dev/null
+++ b/horizon/files/local_settings/liberty_settings.py
@@ -0,0 +1,64 @@
+import os
+from django.utils.translation import ugettext_lazy as _
+from openstack_dashboard import exceptions
+
+{%- from "horizon/map.jinja" import server with context %}
+
+{%- if server.app is defined %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+{%- else %}
+{%- set app = salt['pillar.get']('horizon:server') %}
+{%- endif %}
+
+HORIZON_CONFIG = {
+ 'user_home': 'openstack_dashboard.views.get_user_home',
+ 'ajax_queue_limit': 10,
+ 'auto_fade_alerts': {
+ 'delay': 3000,
+ 'fade_duration': 1500,
+ 'types': ['alert-success', 'alert-info']
+ },
+ 'help_url': "http://docs.openstack.org",
+ 'exceptions': {'recoverable': exceptions.RECOVERABLE,
+ 'not_found': exceptions.NOT_FOUND,
+ 'unauthorized': exceptions.UNAUTHORIZED},
+ 'modal_backdrop': 'static',
+ 'angular_modules': [],
+ 'js_files': [],
+ 'js_spec_files': [],
+ 'password_autocomplete': 'on'
+}
+{%- if app.theme is defined or app.plugin.horizon_theme is defined %}
+{%- if app.theme is defined %}
+CUSTOM_THEME_PATH = 'themes/{{ app.theme }}'
+{%- elif app.plugin.horizon_theme.theme_name is defined %}
+# Enable custom theme if it is present.
+try:
+ from openstack_dashboard.enabled._99_horizon_theme import CUSTOM_THEME_PATH
+except ImportError:
+ pass
+{%- endif %}
+{%- endif %}
+
+INSTALLED_APPS = (
+ 'openstack_dashboard',
+ 'django.contrib.contenttypes',
+ 'django.contrib.auth',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'django.contrib.humanize',
+ 'compressor',
+ 'horizon',
+ 'openstack_auth',
+ {%- if app.logging is defined %}
+ 'raven.contrib.django.raven_compat',
+ {%- endif %}
+)
+
+{% include "horizon/files/horizon_settings/_local_settings.py" %}
+{% include "horizon/files/horizon_settings/_horizon_settings.py" %}
+{% include "horizon/files/horizon_settings/_keystone_settings.py" %}
+{% include "horizon/files/horizon_settings/_nova_settings.py" %}
+{% include "horizon/files/horizon_settings/_glance_settings.py" %}
+{% include "horizon/files/horizon_settings/_neutron_settings.py" %}
diff --git a/horizon/files/local_settings/mitaka_settings.py b/horizon/files/local_settings/mitaka_settings.py
new file mode 100644
index 0000000..47e3587
--- /dev/null
+++ b/horizon/files/local_settings/mitaka_settings.py
@@ -0,0 +1,64 @@
+import os
+from django.utils.translation import ugettext_lazy as _
+from openstack_dashboard import exceptions
+
+{%- from "horizon/map.jinja" import server with context %}
+
+{%- if server.app is defined %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+{%- else %}
+{%- set app = salt['pillar.get']('horizon:server') %}
+{%- endif %}
+
+HORIZON_CONFIG = {
+ 'user_home': 'openstack_dashboard.views.get_user_home',
+ 'ajax_queue_limit': 10,
+ 'auto_fade_alerts': {
+ 'delay': 3000,
+ 'fade_duration': 1500,
+ 'types': ['alert-success', 'alert-info']
+ },
+ 'help_url': "http://docs.openstack.org",
+ 'exceptions': {'recoverable': exceptions.RECOVERABLE,
+ 'not_found': exceptions.NOT_FOUND,
+ 'unauthorized': exceptions.UNAUTHORIZED},
+ 'modal_backdrop': 'static',
+ 'angular_modules': [],
+ 'js_files': [],
+ 'js_spec_files': [],
+ 'password_autocomplete': 'on'
+}
+{%- if app.theme is defined or app.plugin.horizon_theme is defined %}
+{%- if app.theme is defined %}
+CUSTOM_THEME_PATH = 'themes/{{ app.theme }}'
+{%- elif app.plugin.horizon_theme.theme_name is defined %}
+# Enable custom theme if it is present.
+try:
+ from openstack_dashboard.enabled._99_horizon_theme import CUSTOM_THEME_PATH
+except ImportError:
+ pass
+{%- endif %}
+{%- endif %}
+
+INSTALLED_APPS = (
+ 'openstack_dashboard',
+ 'django.contrib.contenttypes',
+ 'django.contrib.auth',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'django.contrib.humanize',
+ 'compressor',
+ 'horizon',
+ 'openstack_auth',
+ {%- if app.logging is defined %}
+ 'raven.contrib.django.raven_compat',
+ {%- endif %}
+)
+
+{% include "horizon/files/horizon_settings/_local_settings.py" %}
+{% include "horizon/files/horizon_settings/_horizon_settings.py" %}
+{% include "horizon/files/horizon_settings/_keystone_settings.py" %}
+{% include "horizon/files/horizon_settings/_nova_settings.py" %}
+{% include "horizon/files/horizon_settings/_glance_settings.py" %}
+{% include "horizon/files/horizon_settings/_neutron_settings.py" %}
diff --git a/horizon/files/local_settings/robotice_settings.py b/horizon/files/local_settings/robotice_settings.py
new file mode 100644
index 0000000..594da1c
--- /dev/null
+++ b/horizon/files/local_settings/robotice_settings.py
@@ -0,0 +1,46 @@
+import os
+from django.utils.translation import ugettext_lazy as _
+from openstack_dashboard import exceptions
+
+{%- from "horizon/map.jinja" import server with context %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+
+HORIZON_CONFIG = {
+ 'dashboards': ({% if app.plugin is defined %}{% for plugin_name, plugin in app.plugin.iteritems() %}{% if plugin.get('dashboard', False) %}'{{ plugin_name }}', {% endif %}{% endfor %}{% endif %}'admin', 'settings'),
+ 'default_dashboard': '{{ app.get('default_dashboard', 'project') }}',
+ 'user_home': '{{ app.get('user_home', 'openstack_dashboard.views.get_user_home') }}',
+ 'ajax_queue_limit': 10,
+ 'auto_fade_alerts': {
+ 'delay': 3000,
+ 'fade_duration': 1500,
+ 'types': ['alert-success', 'alert-info']
+ },
+ 'help_url': "{{ app.get('help_url', 'http://docs.openstack.org') }}",
+ 'exceptions': {'recoverable': exceptions.RECOVERABLE,
+ 'not_found': exceptions.NOT_FOUND,
+ 'unauthorized': exceptions.UNAUTHORIZED},
+ 'password_autocomplete': 'on'
+}
+
+INSTALLED_APPS = (
+ 'robotice_dashboard.dashboards.location',
+ 'robotice_dashboard.dashboards.admin',
+ 'robotice_auth',
+ 'openstack_dashboard',
+ 'django.contrib.contenttypes',
+ 'django.contrib.auth',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'django.contrib.humanize',
+ 'compressor',
+ 'horizon',
+ 'openstack_auth',
+ 'bootstrap3_datetime',
+ {%- if app.logging is defined %}
+ 'raven.contrib.django.raven_compat',
+ {%- endif %}
+)
+
+{% include "horizon/files/horizon_settings/_local_settings.py" %}
+{% include "horizon/files/horizon_settings/_horizon_settings.py" %}
diff --git a/horizon/files/manage.py b/horizon/files/manage.py
new file mode 100644
index 0000000..901330d
--- /dev/null
+++ b/horizon/files/manage.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+
+import sys
+import os
+
+from os.path import join
+
+path = '/srv/horizon'
+
+sys.path.append(join(path, 'sites', '{{ app_name }}', 'lib', 'python2.7', 'site-packages'))
+sys.path.append(join(path, 'sites', '{{ app_name }}', 'extra'))
+{%- if app.plugin is defined %}
+{%- for plugin_name, plugin in app.plugin.iteritems() %}
+sys.path.append(join(path, 'sites', '{{ app_name }}', 'plugins', '{{ plugin_name }}'))
+{%- endfor %}
+{%- endif %}
+
+from django.core.management import execute_from_command_line
+
+if __name__ == "__main__":
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ app.get('dashboard', 'openstack') }}_dashboard.settings")
+ execute_from_command_line(sys.argv)
diff --git a/horizon/files/nginx.conf b/horizon/files/nginx.conf
new file mode 100644
index 0000000..435babd
--- /dev/null
+++ b/horizon/files/nginx.conf
@@ -0,0 +1,61 @@
+{%- set site = salt['pillar.get']('nginx:server:site:'+site_name) %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+site.name) %}
+
+upstream horizon_server_{{ site_name }} {
+ server localhost:{{ app.bind.port }} fail_timeout=0;
+}
+
+server {
+
+ {%- include "nginx/files/_name.conf" %}
+ {%- include "nginx/files/_log.conf" %}
+ {%- include "nginx/files/_ssl.conf" %}
+
+ underscores_in_headers on;
+
+ keepalive_timeout 32;
+
+ root /srv/horizon/sites/{{ site.name }};
+
+ proxy_buffers 8 16k;
+ proxy_buffer_size 32k;
+
+ {%- if site.timeout is defined %}
+ proxy_connect_timeout {{ site.timeout }};
+ proxy_send_timeout {{ site.timeout }};
+ proxy_read_timeout {{ site.timeout }};
+ send_timeout {{ site.timeout }};
+ {%- else %}
+ proxy_connect_timeout 600;
+ proxy_send_timeout 600;
+ proxy_read_timeout 600;
+ send_timeout 600;
+ {%- endif %}
+
+ location /static {
+ autoindex on;
+ alias /srv/horizon/sites/{{ site.name }}/static;
+ }
+
+ location /media {
+ autoindex on;
+ alias /srv/horizon/sites/{{ site.name }}/media;
+ }
+
+ location / {
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Host $http_host;
+ proxy_redirect off;
+
+ proxy_buffer_size 128k;
+ proxy_buffers 4 256k;
+ proxy_busy_buffers_size 256k;
+
+ client_max_body_size 20000m;
+
+ if (!-f $request_filename) {
+ proxy_pass http://horizon_server_{{ site_name }};
+ break;
+ }
+ }
+}
diff --git a/horizon/files/openstack-dashboard.conf.Debian b/horizon/files/openstack-dashboard.conf.Debian
new file mode 100644
index 0000000..40942a2
--- /dev/null
+++ b/horizon/files/openstack-dashboard.conf.Debian
@@ -0,0 +1,56 @@
+{%- from "horizon/map.jinja" import server with context %}
+
+WSGIScriptAlias / /usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi
+WSGIDaemonProcess horizon user=horizon group=horizon processes={{ server.wsgi.processes }} threads={{ server.wsgi.threads }}
+WSGIProcessGroup horizon
+
+Alias /static /usr/share/openstack-dashboard/static
+
+<Directory /usr/share/openstack-dashboard/openstack_dashboard/wsgi>
+ Order allow,deny
+ Allow from all
+</Directory>
+
+<Directory /usr/share/openstack-dashboard/static>
+ <IfModule mod_expires.c>
+ ExpiresActive On
+ ExpiresDefault "access 6 month"
+ </IfModule>
+ <IfModule mod_deflate.c>
+ SetOutputFilter DEFLATE
+ </IfModule>
+
+ Require all granted
+</Directory>
+
+{% if server.get('ssl', {}).get('enabled', False) %}
+
+<VirtualHost {{ server.bind.address }}:443>
+ ServerName {{ server.host.name }}
+
+ SSLEngine On
+ SSLProtocol +TLSv1 +TLSv1.1 +TLSv1.2
+ SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!EXP:!LOW:!MEDIUM
+ SSLCertificateFile {{ server.certs_dir }}/{{ server.host.name }}.crt
+ SSLCertificateKeyFile {{ server.private_dir }}/{{ server.host.name }}.key
+ SSLCertificateChainFile {{ server.certs_dir }}/{{ server.ssl.authority }}-chain.crt
+ SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown/
+
+ WSGIScriptAlias / /usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi
+ Alias /static /usr/share/openstack-dashboard/static
+
+ <Directory /usr/share/openstack-dashboard/openstack_dashboard/wsgi>
+ <IfModule mod_deflate.c>
+ SetOutputFilter DEFLATE
+ <IfModule mod_headers.c>
+ # Make sure proxies don’t deliver the wrong content
+ Header append Vary User-Agent env=!dont-vary
+ </IfModule>
+ </IfModule>
+
+ Order allow,deny
+ Allow from all
+ </Directory>
+</VirtualHost>
+
+{% endif %}
\ No newline at end of file
diff --git a/horizon/files/openstack-dashboard.conf.RedHat b/horizon/files/openstack-dashboard.conf.RedHat
new file mode 100644
index 0000000..00852fc
--- /dev/null
+++ b/horizon/files/openstack-dashboard.conf.RedHat
@@ -0,0 +1,66 @@
+{% from "horizon/map.jinja" import server with context %}
+
+WSGIDaemonProcess dashboard
+WSGIProcessGroup dashboard
+WSGISocketPrefix run/wsgi
+
+WSGIScriptAlias / /usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi
+Alias /static /usr/share/openstack-dashboard/static
+
+<Directory /usr/share/openstack-dashboard/openstack_dashboard/wsgi>
+ <IfModule mod_deflate.c>
+ SetOutputFilter DEFLATE
+ <IfModule mod_headers.c>
+ # Make sure proxies don’t deliver the wrong content
+ Header append Vary User-Agent env=!dont-vary
+ </IfModule>
+ </IfModule>
+
+ Order allow,deny
+ Allow from all
+</Directory>
+
+<Directory /usr/share/openstack-dashboard/static>
+ <IfModule mod_expires.c>
+ ExpiresActive On
+ ExpiresDefault "access 6 month"
+ </IfModule>
+ <IfModule mod_deflate.c>
+ SetOutputFilter DEFLATE
+ </IfModule>
+
+ Order allow,deny
+ Allow from all
+</Directory>
+
+{% if server.get('ssl', {}).get('enabled', False) %}
+
+<VirtualHost {{ server.bind.address }}:443>
+ ServerName {{ server.host.name }}
+
+ SSLEngine On
+ SSLProtocol +TLSv1 +TLSv1.1 +TLSv1.2
+ SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!EXP:!LOW:!MEDIUM
+ SSLCertificateFile {{ server.certs_dir }}/{{ server.host.name }}.crt
+ SSLCertificateKeyFile {{ server.private_dir }}/{{ server.host.name }}.key
+ SSLCertificateChainFile {{ server.certs_dir }}/{{ server.ssl.authority }}-chain.crt
+ SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown/
+
+ WSGIScriptAlias / /usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi
+ Alias /static /usr/share/openstack-dashboard/static
+
+ <Directory /usr/share/openstack-dashboard/openstack_dashboard/wsgi>
+ <IfModule mod_deflate.c>
+ SetOutputFilter DEFLATE
+ <IfModule mod_headers.c>
+ # Make sure proxies don’t deliver the wrong content
+ Header append Vary User-Agent env=!dont-vary
+ </IfModule>
+ </IfModule>
+
+ Order allow,deny
+ Allow from all
+ </Directory>
+</VirtualHost>
+
+{% endif %}
\ No newline at end of file
diff --git a/horizon/files/policy/juno-keystone-v2.json b/horizon/files/policy/juno-keystone-v2.json
new file mode 100644
index 0000000..af65205
--- /dev/null
+++ b/horizon/files/policy/juno-keystone-v2.json
@@ -0,0 +1,171 @@
+{
+ "admin_required": "role:admin or is_admin:1",
+ "service_role": "role:service",
+ "service_or_admin": "rule:admin_required or rule:service_role",
+ "owner" : "user_id:%(user_id)s",
+ "admin_or_owner": "rule:admin_required or rule:owner",
+
+ "default": "rule:admin_required",
+
+ "identity:get_region": "",
+ "identity:list_regions": "",
+ "identity:create_region": "rule:admin_required",
+ "identity:update_region": "rule:admin_required",
+ "identity:delete_region": "rule:admin_required",
+
+ "identity:get_service": "rule:admin_required",
+ "identity:list_services": "rule:admin_required",
+ "identity:create_service": "rule:admin_required",
+ "identity:update_service": "rule:admin_required",
+ "identity:delete_service": "rule:admin_required",
+
+ "identity:get_endpoint": "rule:admin_required",
+ "identity:list_endpoints": "rule:admin_required",
+ "identity:create_endpoint": "rule:admin_required",
+ "identity:update_endpoint": "rule:admin_required",
+ "identity:delete_endpoint": "rule:admin_required",
+
+ "identity:get_domain": "rule:admin_required",
+ "identity:list_domains": "rule:admin_required",
+ "identity:create_domain": "rule:admin_required",
+ "identity:update_domain": "rule:admin_required",
+ "identity:delete_domain": "rule:admin_required",
+
+ "identity:get_project": "rule:admin_required",
+ "identity:list_projects": "rule:admin_required",
+ "identity:list_user_projects": "rule:admin_or_owner",
+ "identity:create_project": "rule:admin_required",
+ "identity:update_project": "rule:admin_required",
+ "identity:delete_project": "rule:admin_required",
+
+ "identity:get_user": "rule:admin_required",
+ "identity:list_users": "rule:admin_required",
+ "identity:create_user": "rule:admin_required",
+ "identity:update_user": "rule:admin_required",
+ "identity:delete_user": "rule:admin_required",
+ "identity:change_password": "rule:admin_or_owner",
+
+ "identity:get_group": "rule:admin_required",
+ "identity:list_groups": "rule:admin_required",
+ "identity:list_groups_for_user": "rule:admin_or_owner",
+ "identity:create_group": "rule:admin_required",
+ "identity:update_group": "rule:admin_required",
+ "identity:delete_group": "rule:admin_required",
+ "identity:list_users_in_group": "rule:admin_required",
+ "identity:remove_user_from_group": "rule:admin_required",
+ "identity:check_user_in_group": "rule:admin_required",
+ "identity:add_user_to_group": "rule:admin_required",
+
+ "identity:get_credential": "rule:admin_required",
+ "identity:list_credentials": "rule:admin_required",
+ "identity:create_credential": "rule:admin_required",
+ "identity:update_credential": "rule:admin_required",
+ "identity:delete_credential": "rule:admin_required",
+
+ "identity:ec2_get_credential": "rule:admin_or_owner",
+ "identity:ec2_list_credentials": "rule:admin_or_owner",
+ "identity:ec2_create_credential": "rule:admin_or_owner",
+ "identity:ec2_delete_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",
+
+ "identity:get_role": "rule:admin_required",
+ "identity:list_roles": "rule:admin_required",
+ "identity:create_role": "rule:admin_required",
+ "identity:update_role": "rule:admin_required",
+ "identity:delete_role": "rule:admin_required",
+
+ "identity:check_grant": "rule:admin_required",
+ "identity:list_grants": "rule:admin_required",
+ "identity:create_grant": "rule:admin_required",
+ "identity:revoke_grant": "rule:admin_required",
+
+ "identity:list_role_assignments": "rule:admin_required",
+
+ "identity:get_policy": "rule:admin_required",
+ "identity:list_policies": "rule:admin_required",
+ "identity:create_policy": "rule:admin_required",
+ "identity:update_policy": "rule:admin_required",
+ "identity:delete_policy": "rule:admin_required",
+
+ "identity:check_token": "rule:admin_required",
+ "identity:validate_token": "rule:service_or_admin",
+ "identity:validate_token_head": "rule:service_or_admin",
+ "identity:revocation_list": "rule:service_or_admin",
+ "identity:revoke_token": "rule:admin_or_owner",
+
+ "identity:create_trust": "user_id:%(trust.trustor_user_id)s",
+ "identity:get_trust": "rule:admin_or_owner",
+ "identity:list_trusts": "",
+ "identity:list_roles_for_trust": "",
+ "identity:check_role_for_trust": "",
+ "identity:get_role_for_trust": "",
+ "identity:delete_trust": "",
+
+ "identity:create_consumer": "rule:admin_required",
+ "identity:get_consumer": "rule:admin_required",
+ "identity:list_consumers": "rule:admin_required",
+ "identity:delete_consumer": "rule:admin_required",
+ "identity:update_consumer": "rule:admin_required",
+
+ "identity:authorize_request_token": "rule:admin_required",
+ "identity:list_access_token_roles": "rule:admin_required",
+ "identity:get_access_token_role": "rule:admin_required",
+ "identity:list_access_tokens": "rule:admin_required",
+ "identity:get_access_token": "rule:admin_required",
+ "identity:delete_access_token": "rule:admin_required",
+
+ "identity:list_projects_for_endpoint": "rule:admin_required",
+ "identity:add_endpoint_to_project": "rule:admin_required",
+ "identity:check_endpoint_in_project": "rule:admin_required",
+ "identity:list_endpoints_for_project": "rule:admin_required",
+ "identity:remove_endpoint_from_project": "rule:admin_required",
+
+ "identity:create_endpoint_group": "rule:admin_required",
+ "identity:list_endpoint_groups": "rule:admin_required",
+ "identity:get_endpoint_group": "rule:admin_required",
+ "identity:update_endpoint_group": "rule:admin_required",
+ "identity:delete_endpoint_group": "rule:admin_required",
+ "identity:list_projects_associated_with_endpoint_group": "rule:admin_required",
+ "identity:list_endpoints_associated_with_endpoint_group": "rule:admin_required",
+ "identity:list_endpoint_groups_for_project": "rule:admin_required",
+ "identity:add_endpoint_group_to_project": "rule:admin_required",
+ "identity:remove_endpoint_group_from_project": "rule:admin_required",
+
+ "identity:create_identity_provider": "rule:admin_required",
+ "identity:list_identity_providers": "rule:admin_required",
+ "identity:get_identity_providers": "rule:admin_required",
+ "identity:update_identity_provider": "rule:admin_required",
+ "identity:delete_identity_provider": "rule:admin_required",
+
+ "identity:create_protocol": "rule:admin_required",
+ "identity:update_protocol": "rule:admin_required",
+ "identity:get_protocol": "rule:admin_required",
+ "identity:list_protocols": "rule:admin_required",
+ "identity:delete_protocol": "rule:admin_required",
+
+ "identity:create_mapping": "rule:admin_required",
+ "identity:get_mapping": "rule:admin_required",
+ "identity:list_mappings": "rule:admin_required",
+ "identity:delete_mapping": "rule:admin_required",
+ "identity:update_mapping": "rule:admin_required",
+
+ "identity:get_auth_catalog": "",
+ "identity:get_auth_projects": "",
+ "identity:get_auth_domains": "",
+
+ "identity:list_projects_for_groups": "",
+ "identity:list_domains_for_groups": "",
+
+ "identity:list_revoke_events": "",
+
+ "identity:create_policy_association_for_endpoint": "rule:admin_required",
+ "identity:check_policy_association_for_endpoint": "rule:admin_required",
+ "identity:delete_policy_association_for_endpoint": "rule:admin_required",
+ "identity:create_policy_association_for_service": "rule:admin_required",
+ "identity:check_policy_association_for_service": "rule:admin_required",
+ "identity:delete_policy_association_for_service": "rule:admin_required",
+ "identity:create_policy_association_for_region_and_service": "rule:admin_required",
+ "identity:check_policy_association_for_region_and_service": "rule:admin_required",
+ "identity:delete_policy_association_for_region_and_service": "rule:admin_required",
+ "identity:get_policy_for_endpoint": "rule:admin_required",
+ "identity:list_endpoints_for_policy": "rule:admin_required"
+}
diff --git a/horizon/files/policy/kilo-keystone-v2.json b/horizon/files/policy/kilo-keystone-v2.json
new file mode 100644
index 0000000..2b88c53
--- /dev/null
+++ b/horizon/files/policy/kilo-keystone-v2.json
@@ -0,0 +1,184 @@
+{
+ "admin_required": "role:admin or is_admin:1",
+ "service_role": "role:service",
+ "service_or_admin": "rule:admin_required or rule:service_role",
+ "owner" : "user_id:%(user_id)s",
+ "admin_or_owner": "rule:admin_required or rule:owner",
+ "token_subject": "user_id:%(target.token.user_id)s",
+ "admin_or_token_subject": "rule:admin_required or rule:token_subject",
+ "service_admin_or_token_subject": "rule:service_or_admin or rule:token_subject",
+
+ "default": "rule:admin_required",
+
+ "identity:get_region": "",
+ "identity:list_regions": "",
+ "identity:create_region": "rule:admin_required",
+ "identity:update_region": "rule:admin_required",
+ "identity:delete_region": "rule:admin_required",
+
+ "identity:get_service": "rule:admin_required",
+ "identity:list_services": "rule:admin_required",
+ "identity:create_service": "rule:admin_required",
+ "identity:update_service": "rule:admin_required",
+ "identity:delete_service": "rule:admin_required",
+
+ "identity:get_endpoint": "rule:admin_required",
+ "identity:list_endpoints": "rule:admin_required",
+ "identity:create_endpoint": "rule:admin_required",
+ "identity:update_endpoint": "rule:admin_required",
+ "identity:delete_endpoint": "rule:admin_required",
+
+ "identity:get_domain": "rule:admin_required",
+ "identity:list_domains": "rule:admin_required",
+ "identity:create_domain": "rule:admin_required",
+ "identity:update_domain": "rule:admin_required",
+ "identity:delete_domain": "rule:admin_required",
+
+ "identity:get_project": "rule:admin_required",
+ "identity:list_projects": "rule:admin_required",
+ "identity:list_user_projects": "rule:admin_or_owner",
+ "identity:create_project": "rule:admin_required",
+ "identity:update_project": "rule:admin_required",
+ "identity:delete_project": "rule:admin_required",
+
+ "identity:get_user": "rule:admin_required",
+ "identity:list_users": "rule:admin_required",
+ "identity:create_user": "rule:admin_required",
+ "identity:update_user": "rule:admin_required",
+ "identity:delete_user": "rule:admin_required",
+ "identity:change_password": "rule:admin_or_owner",
+
+ "identity:get_group": "rule:admin_required",
+ "identity:list_groups": "rule:admin_required",
+ "identity:list_groups_for_user": "rule:admin_or_owner",
+ "identity:create_group": "rule:admin_required",
+ "identity:update_group": "rule:admin_required",
+ "identity:delete_group": "rule:admin_required",
+ "identity:list_users_in_group": "rule:admin_required",
+ "identity:remove_user_from_group": "rule:admin_required",
+ "identity:check_user_in_group": "rule:admin_required",
+ "identity:add_user_to_group": "rule:admin_required",
+
+ "identity:get_credential": "rule:admin_required",
+ "identity:list_credentials": "rule:admin_required",
+ "identity:create_credential": "rule:admin_required",
+ "identity:update_credential": "rule:admin_required",
+ "identity:delete_credential": "rule:admin_required",
+
+ "identity:ec2_get_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",
+ "identity:ec2_list_credentials": "rule:admin_or_owner",
+ "identity:ec2_create_credential": "rule:admin_or_owner",
+ "identity:ec2_delete_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",
+
+ "identity:get_role": "rule:admin_required",
+ "identity:list_roles": "rule:admin_required",
+ "identity:create_role": "rule:admin_required",
+ "identity:update_role": "rule:admin_required",
+ "identity:delete_role": "rule:admin_required",
+
+ "identity:check_grant": "rule:admin_required",
+ "identity:list_grants": "rule:admin_required",
+ "identity:create_grant": "rule:admin_required",
+ "identity:revoke_grant": "rule:admin_required",
+
+ "identity:list_role_assignments": "rule:admin_required",
+
+ "identity:get_policy": "rule:admin_required",
+ "identity:list_policies": "rule:admin_required",
+ "identity:create_policy": "rule:admin_required",
+ "identity:update_policy": "rule:admin_required",
+ "identity:delete_policy": "rule:admin_required",
+
+ "identity:check_token": "rule:admin_or_token_subject",
+ "identity:validate_token": "rule:service_admin_or_token_subject",
+ "identity:validate_token_head": "rule:service_or_admin",
+ "identity:revocation_list": "rule:service_or_admin",
+ "identity:revoke_token": "rule:admin_or_token_subject",
+
+ "identity:create_trust": "user_id:%(trust.trustor_user_id)s",
+ "identity:list_trusts": "",
+ "identity:list_roles_for_trust": "",
+ "identity:get_role_for_trust": "",
+ "identity:delete_trust": "",
+
+ "identity:create_consumer": "rule:admin_required",
+ "identity:get_consumer": "rule:admin_required",
+ "identity:list_consumers": "rule:admin_required",
+ "identity:delete_consumer": "rule:admin_required",
+ "identity:update_consumer": "rule:admin_required",
+
+ "identity:authorize_request_token": "rule:admin_required",
+ "identity:list_access_token_roles": "rule:admin_required",
+ "identity:get_access_token_role": "rule:admin_required",
+ "identity:list_access_tokens": "rule:admin_required",
+ "identity:get_access_token": "rule:admin_required",
+ "identity:delete_access_token": "rule:admin_required",
+
+ "identity:list_projects_for_endpoint": "rule:admin_required",
+ "identity:add_endpoint_to_project": "rule:admin_required",
+ "identity:check_endpoint_in_project": "rule:admin_required",
+ "identity:list_endpoints_for_project": "rule:admin_required",
+ "identity:remove_endpoint_from_project": "rule:admin_required",
+
+ "identity:create_endpoint_group": "rule:admin_required",
+ "identity:list_endpoint_groups": "rule:admin_required",
+ "identity:get_endpoint_group": "rule:admin_required",
+ "identity:update_endpoint_group": "rule:admin_required",
+ "identity:delete_endpoint_group": "rule:admin_required",
+ "identity:list_projects_associated_with_endpoint_group": "rule:admin_required",
+ "identity:list_endpoints_associated_with_endpoint_group": "rule:admin_required",
+ "identity:get_endpoint_group_in_project": "rule:admin_required",
+ "identity:list_endpoint_groups_for_project": "rule:admin_required",
+ "identity:add_endpoint_group_to_project": "rule:admin_required",
+ "identity:remove_endpoint_group_from_project": "rule:admin_required",
+
+ "identity:create_identity_provider": "rule:admin_required",
+ "identity:list_identity_providers": "rule:admin_required",
+ "identity:get_identity_providers": "rule:admin_required",
+ "identity:update_identity_provider": "rule:admin_required",
+ "identity:delete_identity_provider": "rule:admin_required",
+
+ "identity:create_protocol": "rule:admin_required",
+ "identity:update_protocol": "rule:admin_required",
+ "identity:get_protocol": "rule:admin_required",
+ "identity:list_protocols": "rule:admin_required",
+ "identity:delete_protocol": "rule:admin_required",
+
+ "identity:create_mapping": "rule:admin_required",
+ "identity:get_mapping": "rule:admin_required",
+ "identity:list_mappings": "rule:admin_required",
+ "identity:delete_mapping": "rule:admin_required",
+ "identity:update_mapping": "rule:admin_required",
+
+ "identity:create_service_provider": "rule:admin_required",
+ "identity:list_service_providers": "rule:admin_required",
+ "identity:get_service_provider": "rule:admin_required",
+ "identity:update_service_provider": "rule:admin_required",
+ "identity:delete_service_provider": "rule:admin_required",
+
+ "identity:get_auth_catalog": "",
+ "identity:get_auth_projects": "",
+ "identity:get_auth_domains": "",
+
+ "identity:list_projects_for_groups": "",
+ "identity:list_domains_for_groups": "",
+
+ "identity:list_revoke_events": "",
+
+ "identity:create_policy_association_for_endpoint": "rule:admin_required",
+ "identity:check_policy_association_for_endpoint": "rule:admin_required",
+ "identity:delete_policy_association_for_endpoint": "rule:admin_required",
+ "identity:create_policy_association_for_service": "rule:admin_required",
+ "identity:check_policy_association_for_service": "rule:admin_required",
+ "identity:delete_policy_association_for_service": "rule:admin_required",
+ "identity:create_policy_association_for_region_and_service": "rule:admin_required",
+ "identity:check_policy_association_for_region_and_service": "rule:admin_required",
+ "identity:delete_policy_association_for_region_and_service": "rule:admin_required",
+ "identity:get_policy_for_endpoint": "rule:admin_required",
+ "identity:list_endpoints_for_policy": "rule:admin_required",
+
+ "identity:create_domain_config": "rule:admin_required",
+ "identity:get_domain_config": "rule:admin_required",
+ "identity:update_domain_config": "rule:admin_required",
+ "identity:delete_domain_config": "rule:admin_required"
+}
\ No newline at end of file
diff --git a/horizon/files/policy/kilo-keystone-v3.json b/horizon/files/policy/kilo-keystone-v3.json
new file mode 100644
index 0000000..d0e3e64
--- /dev/null
+++ b/horizon/files/policy/kilo-keystone-v3.json
@@ -0,0 +1,195 @@
+{
+ "admin_required": "role:admin",
+ "cloud_admin": "rule:admin_required and domain_id:default",
+ "service_role": "role:service",
+ "service_or_admin": "rule:admin_required or rule:service_role",
+ "owner" : "user_id:%(user_id)s or user_id:%(target.token.user_id)s",
+ "admin_or_owner": "(rule:admin_required and domain_id:%(target.token.user.domain.id)s) or rule:owner",
+ "admin_or_cloud_admin": "rule:admin_required or rule:cloud_admin",
+ "admin_and_matching_domain_id": "rule:admin_required and domain_id:%(domain_id)s",
+ "service_admin_or_owner": "rule:service_or_admin or rule:owner",
+
+ "default": "rule:admin_required",
+
+ "identity:get_region": "",
+ "identity:list_regions": "",
+ "identity:create_region": "rule:cloud_admin",
+ "identity:update_region": "rule:cloud_admin",
+ "identity:delete_region": "rule:cloud_admin",
+
+ "identity:get_service": "rule:admin_or_cloud_admin",
+ "identity:list_services": "rule:admin_or_cloud_admin",
+ "identity:create_service": "rule:cloud_admin",
+ "identity:update_service": "rule:cloud_admin",
+ "identity:delete_service": "rule:cloud_admin",
+
+ "identity:get_endpoint": "rule:admin_or_cloud_admin",
+ "identity:list_endpoints": "rule:admin_or_cloud_admin",
+ "identity:create_endpoint": "rule:cloud_admin",
+ "identity:update_endpoint": "rule:cloud_admin",
+ "identity:delete_endpoint": "rule:cloud_admin",
+
+ "identity:get_domain": "rule:cloud_admin or rule:admin_and_matching_domain_id",
+ "identity:list_domains": "rule:cloud_admin",
+ "identity:create_domain": "rule:cloud_admin",
+ "identity:update_domain": "rule:cloud_admin",
+ "identity:delete_domain": "rule:cloud_admin",
+
+ "admin_and_matching_target_project_domain_id": "rule:admin_required and domain_id:%(target.project.domain_id)s",
+ "admin_and_matching_project_domain_id": "rule:admin_required and domain_id:%(project.domain_id)s",
+ "identity:get_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id",
+ "identity:list_projects": "rule:cloud_admin or rule:admin_and_matching_domain_id",
+ "identity:list_user_projects": "rule:owner or rule:admin_and_matching_domain_id",
+ "identity:create_project": "rule:cloud_admin or rule:admin_and_matching_project_domain_id",
+ "identity:update_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id",
+ "identity:delete_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id",
+
+ "admin_and_matching_target_user_domain_id": "rule:admin_required and domain_id:%(target.user.domain_id)s",
+ "admin_and_matching_user_domain_id": "rule:admin_required and domain_id:%(user.domain_id)s",
+ "identity:get_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id",
+ "identity:list_users": "rule:cloud_admin or rule:admin_and_matching_domain_id",
+ "identity:create_user": "rule:cloud_admin or rule:admin_and_matching_user_domain_id",
+ "identity:update_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id",
+ "identity:delete_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id",
+
+ "admin_and_matching_target_group_domain_id": "rule:admin_required and domain_id:%(target.group.domain_id)s",
+ "admin_and_matching_group_domain_id": "rule:admin_required and domain_id:%(group.domain_id)s",
+ "identity:get_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+ "identity:list_groups": "rule:cloud_admin or rule:admin_and_matching_domain_id",
+ "identity:list_groups_for_user": "rule:owner or rule:admin_and_matching_domain_id",
+ "identity:create_group": "rule:cloud_admin or rule:admin_and_matching_group_domain_id",
+ "identity:update_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+ "identity:delete_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+ "identity:list_users_in_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+ "identity:remove_user_from_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+ "identity:check_user_in_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+ "identity:add_user_to_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+
+ "identity:get_credential": "rule:admin_required",
+ "identity:list_credentials": "rule:admin_required or user_id:%(user_id)s",
+ "identity:create_credential": "rule:admin_required",
+ "identity:update_credential": "rule:admin_required",
+ "identity:delete_credential": "rule:admin_required",
+
+ "identity:ec2_get_credential": "rule:admin_or_cloud_admin or (rule:owner and user_id:%(target.credential.user_id)s)",
+ "identity:ec2_list_credentials": "rule:admin_or_cloud_admin or rule:owner",
+ "identity:ec2_create_credential": "rule:admin_or_cloud_admin or rule:owner",
+ "identity:ec2_delete_credential": "rule:admin_or_cloud_admin or (rule:owner and user_id:%(target.credential.user_id)s)",
+
+ "identity:get_role": "rule:admin_or_cloud_admin",
+ "identity:list_roles": "rule:admin_or_cloud_admin",
+ "identity:create_role": "rule:cloud_admin",
+ "identity:update_role": "rule:cloud_admin",
+ "identity:delete_role": "rule:cloud_admin",
+
+ "domain_admin_for_grants": "rule:admin_required and (domain_id:%(domain_id)s or domain_id:%(target.project.domain_id)s)",
+ "project_admin_for_grants": "rule:admin_required and project_id:%(project_id)s",
+ "identity:check_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
+ "identity:list_grants": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
+ "identity:create_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
+ "identity:revoke_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
+
+ "admin_on_domain_filter" : "rule:admin_required and domain_id:%(scope.domain.id)s",
+ "admin_on_project_filter" : "rule:admin_required and project_id:%(scope.project.id)s",
+ "identity:list_role_assignments": "rule:cloud_admin or rule:admin_on_domain_filter or rule:admin_on_project_filter",
+
+ "identity:get_policy": "rule:cloud_admin",
+ "identity:list_policies": "rule:cloud_admin",
+ "identity:create_policy": "rule:cloud_admin",
+ "identity:update_policy": "rule:cloud_admin",
+ "identity:delete_policy": "rule:cloud_admin",
+
+ "identity:change_password": "rule:owner",
+ "identity:check_token": "rule:admin_or_owner",
+ "identity:validate_token": "rule:service_admin_or_owner",
+ "identity:validate_token_head": "rule:service_or_admin",
+ "identity:revocation_list": "rule:service_or_admin",
+ "identity:revoke_token": "rule:admin_or_owner",
+
+ "identity:create_trust": "user_id:%(trust.trustor_user_id)s",
+ "identity:list_trusts": "",
+ "identity:list_roles_for_trust": "",
+ "identity:get_role_for_trust": "",
+ "identity:delete_trust": "",
+
+ "identity:create_consumer": "rule:admin_required",
+ "identity:get_consumer": "rule:admin_required",
+ "identity:list_consumers": "rule:admin_required",
+ "identity:delete_consumer": "rule:admin_required",
+ "identity:update_consumer": "rule:admin_required",
+
+ "identity:authorize_request_token": "rule:admin_required",
+ "identity:list_access_token_roles": "rule:admin_required",
+ "identity:get_access_token_role": "rule:admin_required",
+ "identity:list_access_tokens": "rule:admin_required",
+ "identity:get_access_token": "rule:admin_required",
+ "identity:delete_access_token": "rule:admin_required",
+
+ "identity:list_projects_for_endpoint": "rule:admin_required",
+ "identity:add_endpoint_to_project": "rule:admin_required",
+ "identity:check_endpoint_in_project": "rule:admin_required",
+ "identity:list_endpoints_for_project": "rule:admin_required",
+ "identity:remove_endpoint_from_project": "rule:admin_required",
+
+ "identity:create_endpoint_group": "rule:admin_required",
+ "identity:list_endpoint_groups": "rule:admin_required",
+ "identity:get_endpoint_group": "rule:admin_required",
+ "identity:update_endpoint_group": "rule:admin_required",
+ "identity:delete_endpoint_group": "rule:admin_required",
+ "identity:list_projects_associated_with_endpoint_group": "rule:admin_required",
+ "identity:list_endpoints_associated_with_endpoint_group": "rule:admin_required",
+ "identity:get_endpoint_group_in_project": "rule:admin_required",
+ "identity:list_endpoint_groups_for_project": "rule:admin_required",
+ "identity:add_endpoint_group_to_project": "rule:admin_required",
+ "identity:remove_endpoint_group_from_project": "rule:admin_required",
+
+ "identity:create_identity_provider": "rule:cloud_admin",
+ "identity:list_identity_providers": "rule:cloud_admin",
+ "identity:get_identity_providers": "rule:cloud_admin",
+ "identity:update_identity_provider": "rule:cloud_admin",
+ "identity:delete_identity_provider": "rule:cloud_admin",
+
+ "identity:create_protocol": "rule:cloud_admin",
+ "identity:update_protocol": "rule:cloud_admin",
+ "identity:get_protocol": "rule:cloud_admin",
+ "identity:list_protocols": "rule:cloud_admin",
+ "identity:delete_protocol": "rule:cloud_admin",
+
+ "identity:create_mapping": "rule:cloud_admin",
+ "identity:get_mapping": "rule:cloud_admin",
+ "identity:list_mappings": "rule:cloud_admin",
+ "identity:delete_mapping": "rule:cloud_admin",
+ "identity:update_mapping": "rule:cloud_admin",
+
+ "identity:create_service_provider": "rule:cloud_admin",
+ "identity:list_service_providers": "rule:cloud_admin",
+ "identity:get_service_provider": "rule:cloud_admin",
+ "identity:update_service_provider": "rule:cloud_admin",
+ "identity:delete_service_provider": "rule:cloud_admin",
+
+ "identity:get_auth_catalog": "",
+ "identity:get_auth_projects": "",
+ "identity:get_auth_domains": "",
+
+ "identity:list_projects_for_groups": "",
+ "identity:list_domains_for_groups": "",
+
+ "identity:list_revoke_events": "",
+
+ "identity:create_policy_association_for_endpoint": "rule:cloud_admin",
+ "identity:check_policy_association_for_endpoint": "rule:cloud_admin",
+ "identity:delete_policy_association_for_endpoint": "rule:cloud_admin",
+ "identity:create_policy_association_for_service": "rule:cloud_admin",
+ "identity:check_policy_association_for_service": "rule:cloud_admin",
+ "identity:delete_policy_association_for_service": "rule:cloud_admin",
+ "identity:create_policy_association_for_region_and_service": "rule:cloud_admin",
+ "identity:check_policy_association_for_region_and_service": "rule:cloud_admin",
+ "identity:delete_policy_association_for_region_and_service": "rule:cloud_admin",
+ "identity:get_policy_for_endpoint": "rule:cloud_admin",
+ "identity:list_endpoints_for_policy": "rule:cloud_admin",
+
+ "identity:create_domain_config": "rule:cloud_admin",
+ "identity:get_domain_config": "rule:cloud_admin",
+ "identity:update_domain_config": "rule:cloud_admin",
+ "identity:delete_domain_config": "rule:cloud_admin"
+}
\ No newline at end of file
diff --git a/horizon/files/ports.conf b/horizon/files/ports.conf
new file mode 100644
index 0000000..3b7254e
--- /dev/null
+++ b/horizon/files/ports.conf
@@ -0,0 +1,16 @@
+{%- from "horizon/map.jinja" import server with context %}
+# If you just change the port or add more ports here, you will likely also
+# have to change the VirtualHost statement in
+# /etc/apache2/sites-enabled/000-default.conf
+
+Listen {{ server.bind.address }}:{{ server.bind.port }}
+
+<IfModule ssl_module>
+ Listen {{ server.bind.address }}:443
+</IfModule>
+
+<IfModule mod_gnutls.c>
+ Listen {{ server.bind.address }}:443
+</IfModule>
+
+# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
diff --git a/horizon/files/requirements/csb_vanilla.txt b/horizon/files/requirements/csb_vanilla.txt
new file mode 100644
index 0000000..bf2a336
--- /dev/null
+++ b/horizon/files/requirements/csb_vanilla.txt
@@ -0,0 +1,67 @@
+# PBR should always appear first
+pbr>=0.6,!=0.7,<1.0
+prettytable>=0.7.2
+stevedore>=1.2.0
+Babel>=1.3
+# Horizon Core Requirements
+Django>=1.4.2,<1.7
+django_compressor>=1.4
+django_openstack_auth>=1.1.7
+django-pyscss>=1.0.3,<=1.0.6 # BSD License (2 clause)
+eventlet>=0.15.1
+httplib2>=0.7.5
+iso8601>=0.1.9
+kombu>=2.5.0
+# Horizon Utility Requirements
+# for SECURE_KEY generation
+lockfile>=0.8
+netaddr>=0.7.12
+pyScss>=1.2.1,<1.3 # MIT License
+python-ceilometerclient>=1.0.6
+python-cinderclient>=1.1.0
+python-glanceclient>=0.14.0
+python-heatclient>=0.2.9
+python-keystoneclient>=0.10.0
+python-neutronclient>=2.3.6,<3
+python-novaclient>=2.18.0
+python-saharaclient>=0.7.3
+python-swiftclient>=2.2.0
+python-troveclient>=1.0.4
+python-mistralclient
+pytz
+six>=1.7.0
+requests==2.1.0
+raven>=3.5.2
+gunicorn>=18.0
+oslo.config==1.12.1 # Apache-2.0
+oslo.i18n==1.7.0 # Apache-2.0
+oslo.serialization==1.6.0 # Apache-2.0
+oslo.utils==1.6.0 # Apache-2.0
+xstatic>=1.0.0 # MIT License
+xstatic-angular>=1.2.1.1 # MIT License
+xstatic-angular-cookies>=1.2.1.1 # MIT License
+xstatic-angular-mock>=1.2.1.1 # 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.1.0 # SIL OFL 1.1 License, MIT License
+xstatic-jasmine>=1.3.1.1 # 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.0.5b.0 # MIT License
+xstatic-jquery-ui>=1.10.1 # MIT License
+xstatic-jsencrypt>=2.0.0.2 # MIT License
+xstatic-qunit>=1.14.0.2 # MIT License
+xstatic-rickshaw>=1.5.0 # BSD License (prior)
+xstatic-spin>=1.2.5.2 # MIT License
+cryptography
+greenlet>=0.4.5
+django-appconf
+django-markitup==2.2.2
+xstatic-adminlte>=2.0.1.1
+django_image_proxy>=0.0.1
+PyYAML>=3.1.0
+python-memcached
+docutils
\ No newline at end of file
diff --git a/horizon/files/requirements/helpdesk_vanilla.txt b/horizon/files/requirements/helpdesk_vanilla.txt
new file mode 100644
index 0000000..bf40f1b
--- /dev/null
+++ b/horizon/files/requirements/helpdesk_vanilla.txt
@@ -0,0 +1,70 @@
+# PBR should always appear first
+pbr>=0.6,!=0.7,<1.0
+# Horizon Core Requirements
+Babel>=1.3
+Django>=1.4.2,<1.7
+Pint>=0.5 # BSD
+django_compressor>=1.4
+django_openstack_auth>=1.1.7,!=1.1.8
+django-pyscss>=1.0.3 # BSD License (2 clause)
+eventlet>=0.16.1
+httplib2>=0.7.5
+iso8601>=0.1.9
+kombu>=2.5.0
+netaddr>=0.7.12
+oslo.concurrency>=1.4.1 # Apache-2.0
+oslo.config>=1.9.0 # Apache-2.0
+oslo.i18n>=1.3.0 # Apache-2.0
+oslo.serialization>=1.2.0 # Apache-2.0
+oslo.utils>=1.2.0 # Apache-2.0
+pyScss>=1.2.1,<1.3 # MIT License
+python-ceilometerclient>=1.0.6
+python-cinderclient>=1.1.0
+python-glanceclient>=0.15.0
+python-heatclient>=0.3.0
+python-keystoneclient>=1.1.0
+python-neutronclient>=2.3.11,<3
+python-novaclient>=2.18.0,!=2.21.0
+python-saharaclient>=0.7.6
+python-swiftclient>=2.2.0
+python-troveclient>=1.0.7
+python-mistralclient
+pytz>=2013.6
+PyYAML>=3.1.0
+six>=1.9.0
+XStatic>=1.0.0 # MIT License
+XStatic-Angular>=1.3.7 # MIT License
+XStatic-Angular-Bootstrap>=0.11.0.2 # MIT License
+XStatic-Angular-Irdragndrop>=1.0.2.1 # 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.2.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.0.5b.0 # MIT License
+XStatic-jquery-ui>=1.10.1 # MIT License
+XStatic-JSEncrypt>=2.0.0.2 # MIT License
+XStatic-QUnit>=1.14.0.2 # MIT 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
+cryptography
+greenlet>=0.4.5
+django-appconf
+stevedore
+gunicorn>=18.0
+python-memcached
+# not listed in global requirements
+beautifulsoup4
+django-floppyforms>=1.1
+yaql>=0.2.3,<0.3
+python-muranoclient>=0.5.5
+raven
+
+horizon-contrib>=2015.11.6
+django-wysiwyg-redactor
\ No newline at end of file
diff --git a/horizon/files/requirements/icehouse_contrail.txt b/horizon/files/requirements/icehouse_contrail.txt
new file mode 100644
index 0000000..d66f956
--- /dev/null
+++ b/horizon/files/requirements/icehouse_contrail.txt
@@ -0,0 +1,39 @@
+# PBR should always appear first
+pbr>=0.6,!=0.7,<1.0
+# Horizon Core Requirements
+Babel>=1.3
+Django>=1.4.2,<1.7
+django_compressor>=1.4
+django_openstack_auth>=1.1.7
+django-pyscss>=1.0.3 # BSD License (2 clause)
+eventlet>=0.15.1
+httplib2>=0.7.5
+iso8601>=0.1.9
+kombu>=2.5.0
+# Horizon Utility Requirements
+# for SECURE_KEY generation
+lockfile>=0.8
+netaddr>=0.7.12
+pyScss>=1.2.1,<1.3 # MIT License
+python-ceilometerclient>=1.0.6
+python-cinderclient>=1.1.0
+python-glanceclient>=0.14.0
+python-heatclient>=0.2.9
+python-keystoneclient>=0.10.0
+-e git+https://github.com/Juniper/python-neutronclient.git@contrail/icehouse#egg=python-neutronclient
+python-novaclient>=2.18.0
+python-saharaclient>=0.7.3
+python-swiftclient>=2.2.0
+python-troveclient>=1.0.4
+pytz
+six>=1.7.0
+requests==2.1.0
+raven>=3.5.2
+gunicorn>=18.0
+oslo.config>=1.4.0 # Apache-2.0
+oslo.i18n>=1.0.0 # Apache-2.0
+oslo.serialization>=1.0.0 # Apache-2.0
+oslo.utils>=1.1.0 # Apache-2.0
+cryptography
+greenlet>=0.4.5
+django-appconf
diff --git a/horizon/files/requirements/icehouse_vanilla.txt b/horizon/files/requirements/icehouse_vanilla.txt
new file mode 100644
index 0000000..3e09189
--- /dev/null
+++ b/horizon/files/requirements/icehouse_vanilla.txt
@@ -0,0 +1,39 @@
+# PBR should always appear first
+pbr>=0.6,!=0.7,<1.0
+# Horizon Core Requirements
+Babel>=1.3
+Django>=1.4.2,<1.7
+django_compressor>=1.4
+django_openstack_auth>=1.1.7
+django-pyscss>=1.0.3 # BSD License (2 clause)
+eventlet>=0.15.1
+httplib2>=0.7.5
+iso8601>=0.1.9
+kombu>=2.5.0
+# Horizon Utility Requirements
+# for SECURE_KEY generation
+lockfile>=0.8
+netaddr>=0.7.12
+pyScss>=1.2.1,<1.3 # MIT License
+python-ceilometerclient>=1.0.6
+python-cinderclient>=1.1.0
+python-glanceclient>=0.14.0
+python-heatclient>=0.2.9
+python-keystoneclient>=0.10.0
+python-neutronclient>=2.3.6,<3
+python-novaclient>=2.18.0
+python-saharaclient>=0.7.3
+python-swiftclient>=2.2.0
+python-troveclient>=1.0.4
+pytz
+six>=1.7.0
+requests==2.1.0
+raven>=3.5.2
+gunicorn>=18.0
+oslo.config>=1.4.0 # Apache-2.0
+oslo.i18n>=1.0.0 # Apache-2.0
+oslo.serialization>=1.0.0 # Apache-2.0
+oslo.utils>=1.1.0 # Apache-2.0
+cryptography
+greenlet>=0.4.5
+django-appconf
diff --git a/horizon/files/requirements/juno_contrail.txt b/horizon/files/requirements/juno_contrail.txt
new file mode 100644
index 0000000..a1c6e98
--- /dev/null
+++ b/horizon/files/requirements/juno_contrail.txt
@@ -0,0 +1,71 @@
+# PBR should always appear first
+pbr>=0.6,!=0.7,<1.0
+# Horizon Core Requirements
+Django>=1.4.2,<1.7
+django_compressor>=1.4,<=1.4
+django_openstack_auth>=1.1.7,!=1.1.8,<=1.1.9
+django-pyscss>=1.0.3,<=1.0.6 # BSD License (2 clause)
+eventlet>=0.15.1,<=0.15.2
+httplib2>=0.7.5,<=0.9
+iso8601>=0.1.9,<=0.1.10
+kombu>=2.5.0,<=3.0.7
+# Horizon Utility Requirements
+# for SECURE_KEY generation
+lockfile>=0.8,<=0.8
+netaddr>=0.7.12,<=0.7.13
+pyScss>=1.2.1,<1.3 # MIT License
+python-ceilometerclient>=1.0.6,<1.0.13
+python-cinderclient>=1.1.0,<=1.1.1
+python-glanceclient>=0.14.0,<=0.15.0
+python-heatclient>=0.2.9,<0.3.0
+python-keystoneclient>=0.10.0,<1.2.0
+-e git+https://github.com/Juniper/python-neutronclient.git@contrail/juno#egg=python-neutronclient
+python-novaclient>=2.18.0,<=2.20.0
+python-troveclient>=1.0.4,<=1.0.8
+python-saharaclient>=0.7.3,<=0.7.6
+python-swiftclient>=2.2.0,<=2.3.1
+pytz
+six>=1.7.0,<=1.9.0
+requests==2.1.0
+raven>=3.5.2
+gunicorn==18.0
+oslo.config==1.12.1 # Apache-2.0
+oslo.i18n==1.7.0 # Apache-2.0
+oslo.serialization==1.6.0 # Apache-2.0
+oslo.utils==1.6.0 # Apache-2.0
+XStatic>=1.0.0 # MIT License
+XStatic-angular>=1.2.1.1,<1.3.0 # MIT License
+XStatic-angular-cookies>=1.2.1.1 # MIT License
+XStatic-angular-mock>=1.2.1.1 # 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.1.0 # SIL OFL 1.1 License, MIT License
+XStatic-jasmine>=1.3.1.1,<2 # 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.0.5b.0 # MIT License
+XStatic-jquery-ui>=1.10.1 # MIT License
+XStatic-jsencrypt>=2.0.0.2 # MIT License
+XStatic-qunit>=1.14.0.2 # MIT License
+XStatic-rickshaw>=1.5.0 # BSD License (prior)
+XStatic-spin>=1.2.5.2 # MIT License
+cryptography
+greenlet>=0.4.5
+django-appconf
+
+# not listed in global requirements
+PyYAML>=3.1.0
+beautifulsoup4
+django-floppyforms>=1.1
+yaql>=0.2.3,<0.3
+python-muranoclient>=0.5.5
+
+#contrail
+argparse
+cliff>=1.6.0
+Babel>=1.3
+simplejson>=2.2.0
+python-memcached
\ No newline at end of file
diff --git a/horizon/files/requirements/juno_vanilla.txt b/horizon/files/requirements/juno_vanilla.txt
new file mode 100644
index 0000000..51949db
--- /dev/null
+++ b/horizon/files/requirements/juno_vanilla.txt
@@ -0,0 +1,66 @@
+# PBR should always appear first
+pbr>=0.6,!=0.7,<1.0
+# Horizon Core Requirements
+Django>=1.4.2,<1.7
+django_compressor>=1.4,<=1.4
+django_openstack_auth>=1.1.7,!=1.1.8,<=1.1.9
+django-pyscss>=1.0.3,<=1.0.6 # BSD License (2 clause)
+eventlet>=0.15.1,<=0.15.2
+httplib2>=0.7.5,<=0.9
+iso8601>=0.1.9,<=0.1.10
+kombu>=2.5.0,<=3.0.7
+# Horizon Utility Requirements
+# for SECURE_KEY generation
+lockfile>=0.8,<=0.8
+netaddr>=0.7.12,<=0.7.13
+pyScss>=1.2.1,<1.3 # MIT License
+python-ceilometerclient>=1.0.6,<1.0.13
+python-cinderclient>=1.1.0,<=1.1.1
+python-glanceclient>=0.14.0,<=0.15.0
+python-heatclient>=0.2.9,<0.3.0
+python-keystoneclient>=0.10.0,<1.2.0
+python-neutronclient>=2.3.6,<2.4.0
+python-novaclient>=2.18.0,<=2.20.0
+python-troveclient>=1.0.4,<=1.0.8
+python-saharaclient>=0.7.3,<=0.7.6
+python-swiftclient>=2.2.0,<=2.3.1
+pytz
+six>=1.7.0
+requests==2.1.0
+raven>=3.5.2
+gunicorn>=18.0
+oslo.config==1.12.1 # Apache-2.0
+oslo.i18n==1.7.0 # Apache-2.0
+oslo.serialization==1.6.0 # Apache-2.0
+oslo.utils==1.6.0 # Apache-2.0
+XStatic>=1.0.0 # MIT License
+XStatic-angular>=1.2.1.1,<1.3.0 # MIT License
+XStatic-angular-cookies>=1.2.1.1 # MIT License
+XStatic-angular-mock>=1.2.1.1 # 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.1.0 # SIL OFL 1.1 License, MIT License
+XStatic-jasmine>=1.3.1.1,<2 # 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.0.5b.0 # MIT License
+XStatic-jquery-ui>=1.10.1 # MIT License
+XStatic-jsencrypt>=2.0.0.2 # MIT License
+XStatic-qunit>=1.14.0.2 # MIT License
+XStatic-rickshaw>=1.5.0 # BSD License (prior)
+XStatic-spin>=1.2.5.2 # MIT License
+cryptography
+greenlet>=0.4.5
+django-appconf
+
+# not listed in global requirements
+PyYAML>=3.1.0
+beautifulsoup4
+django-floppyforms>=1.1
+yaql>=0.2.3,<0.3
+python-muranoclient>=0.5.5
+horizon-contrib>=2015.6.1
+python-memcached
\ No newline at end of file
diff --git a/horizon/files/requirements/kilo_contrail.txt b/horizon/files/requirements/kilo_contrail.txt
new file mode 100644
index 0000000..db24635
--- /dev/null
+++ b/horizon/files/requirements/kilo_contrail.txt
@@ -0,0 +1,75 @@
+# PBR should always appear first
+pbr>=0.6,!=0.7
+# Horizon Core Requirements
+Babel>=1.3
+Django>=1.4.2,<1.7
+Pint>=0.5 # BSD
+django_compressor>=1.4
+django_openstack_auth>=1.1.7,!=1.1.8
+django-pyscss>=1.0.3 # BSD License (2 clause)
+eventlet>=0.16.1
+httplib2>=0.7.5
+iso8601>=0.1.9
+kombu>=2.5.0
+netaddr>=0.7.12
+oslo.concurrency>=1.4.1 # Apache-2.0
+oslo.config>=1.9.0 # Apache-2.0
+oslo.i18n>=1.3.0 # Apache-2.0
+oslo.serialization>=1.2.0 # Apache-2.0
+oslo.utils>=1.2.0 # Apache-2.0
+pyScss>=1.2.1,<1.3 # MIT License
+python-ceilometerclient>=1.0.6
+python-cinderclient>=1.1.0
+python-glanceclient>=0.15.0
+python-heatclient>=0.3.0
+python-keystoneclient>=1.1.0
+python-neutronclient>=2.3.11,<3
+python-novaclient>=2.18.0,!=2.21.0
+python-saharaclient>=0.7.6
+python-swiftclient>=2.2.0
+python-troveclient>=1.0.7
+python-mistralclient
+pytz>=2013.6
+PyYAML>=3.1.0
+six>=1.9.0
+XStatic>=1.0.0 # MIT License
+XStatic-Angular>=1.3.7 # MIT License
+XStatic-Angular-Bootstrap>=0.11.0.2 # MIT License
+XStatic-Angular-Irdragndrop>=1.0.2.1 # 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.2.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.0.5b.0 # MIT License
+XStatic-jquery-ui>=1.10.1 # MIT License
+XStatic-JSEncrypt>=2.0.0.2 # MIT License
+XStatic-QUnit>=1.14.0.2 # MIT 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
+cryptography
+greenlet>=0.4.5
+django-appconf
+stevedore
+gunicorn>=18.0
+
+# not listed in global requirements
+beautifulsoup4
+django-floppyforms>=1.1
+yaql>=0.2.3,<0.3
+python-muranoclient>=0.5.5
+raven
+
+horizon-contrib>=2015.7.6
+
+#contrail
+argparse
+cliff>=1.6.0
+simplejson>=2.2.0
+python-memcached
diff --git a/horizon/files/requirements/kilo_vanilla.txt b/horizon/files/requirements/kilo_vanilla.txt
new file mode 100644
index 0000000..7222d31
--- /dev/null
+++ b/horizon/files/requirements/kilo_vanilla.txt
@@ -0,0 +1,70 @@
+# PBR should always appear first
+pbr>=0.6,!=0.7
+# Horizon Core Requirements
+Babel>=1.3
+Django>=1.4.2,<1.7
+Pint>=0.5 # BSD
+django_compressor>=1.4
+django_openstack_auth>=1.1.7,!=1.1.8
+django-pyscss>=1.0.3 # BSD License (2 clause)
+eventlet>=0.16.1
+httplib2>=0.7.5
+iso8601>=0.1.9
+kombu>=2.5.0
+netaddr>=0.7.12
+oslo.concurrency>=1.4.1 # Apache-2.0
+oslo.config>=1.9.0 # Apache-2.0
+oslo.i18n>=1.3.0 # Apache-2.0
+oslo.serialization>=1.2.0 # Apache-2.0
+oslo.utils>=1.2.0 # Apache-2.0
+pyScss>=1.2.1,<1.3 # MIT License
+python-ceilometerclient>=1.0.6
+python-cinderclient>=1.1.0
+python-glanceclient>=0.15.0
+python-heatclient>=0.3.0
+python-keystoneclient>=1.1.0
+python-neutronclient>=2.3.11,<3
+python-novaclient>=2.18.0,!=2.21.0
+python-saharaclient>=0.7.6
+python-swiftclient>=2.2.0
+python-troveclient>=1.0.7
+python-mistralclient
+pytz>=2013.6
+PyYAML>=3.1.0
+six>=1.9.0
+XStatic>=1.0.0 # MIT License
+XStatic-Angular>=1.3.7 # MIT License
+XStatic-Angular-Bootstrap>=0.11.0.2 # MIT License
+XStatic-Angular-Irdragndrop>=1.0.2.1 # 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.2.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.0.5b.0 # MIT License
+XStatic-jquery-ui>=1.10.1 # MIT License
+XStatic-JSEncrypt>=2.0.0.2 # MIT License
+XStatic-QUnit>=1.14.0.2 # MIT 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
+cryptography
+greenlet>=0.4.5
+django-appconf
+stevedore
+gunicorn>=18.0
+
+# not listed in global requirements
+beautifulsoup4
+django-floppyforms>=1.1
+yaql>=0.2.3,<0.3
+python-muranoclient>=0.5.5
+raven
+
+horizon-contrib>=2015.7.6
+python-memcached
diff --git a/horizon/files/requirements/liberty_contrail.txt b/horizon/files/requirements/liberty_contrail.txt
new file mode 100644
index 0000000..76e111d
--- /dev/null
+++ b/horizon/files/requirements/liberty_contrail.txt
@@ -0,0 +1,89 @@
+# 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>=1.6
+# Horizon Core Requirements
+Babel>=1.3
+Django<1.9,>=1.7
+Pint>=0.5 # BSD
+django-babel>=0.3.4
+django-compressor>=1.4
+django-openstack-auth>=2.0.0
+django-pyscss>=2.0.2 # BSD License (2 clause)
+eventlet>=0.17.4
+gunicorn>=18.0
+httplib2>=0.7.5
+iso8601>=0.1.9
+kombu>=3.0.7
+netaddr!=0.7.16,>=0.7.12
+oslo.concurrency>=2.3.0 # Apache-2.0
+oslo.config>=2.3.0 # Apache-2.0
+oslo.i18n>=1.5.0 # Apache-2.0
+oslo.policy>=0.5.0 # Apache-2.0
+oslo.serialization>=1.4.0 # Apache-2.0
+oslo.utils>=2.0.0 # Apache-2.0
+pyScss>=1.3.4 # MIT License
+python-ceilometerclient>=1.5.0
+python-cinderclient>=1.3.1
+python-glanceclient>=0.18.0
+python-heatclient>=0.3.0
+python-keystoneclient>=1.6.0
+python-neutronclient>=2.6.0
+python-novaclient>=2.28.1
+python-saharaclient>=0.10.0
+python-swiftclient>=2.2.0
+python-troveclient>=1.2.0
+pytz>=2013.6
+PyYAML>=3.1.0
+six>=1.9.0
+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-bootswatch>=3.3.5.3 # MIT 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-mdi==1.1.70.1 # SIL OPEN FONT LICENSE Version 1.1
+XStatic-Rickshaw>=1.5.0 # BSD License (prior)
+XStatic-roboto-fontface>=0.4.3.2 # Apache 2.0 License
+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
+
+horizon-contrib>=2015.10.0
+
+#contrail
+argparse
+cliff>=1.6.0
+simplejson>=2.2.0
+python-memcached
+
+# murano
+beautifulsoup4
+django-formtools
+python-muranoclient>=0.7.1
+yaql>=1.0.0 # Apache 2.0 License
+
+oslo.log>=1.8.0 # Apache-2.0
+semantic-version>=2.3.1
+
+functools32==3.2.3-2
+jsonpointer==1.10
\ No newline at end of file
diff --git a/horizon/files/requirements/liberty_vanilla.txt b/horizon/files/requirements/liberty_vanilla.txt
new file mode 100644
index 0000000..190e111
--- /dev/null
+++ b/horizon/files/requirements/liberty_vanilla.txt
@@ -0,0 +1,72 @@
+# 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>=1.6
+# Horizon Core Requirements
+Babel>=1.3
+Django<1.9,>=1.7
+Pint>=0.5 # BSD
+django-babel>=0.3.4
+django-compressor>=1.4
+django-openstack-auth>=2.0.0
+django-pyscss>=2.0.2 # BSD License (2 clause)
+eventlet>=0.17.4
+gunicorn>=18.0
+httplib2>=0.7.5
+iso8601>=0.1.9
+kombu>=3.0.7
+netaddr!=0.7.16,>=0.7.12
+oslo.concurrency>=2.3.0 # Apache-2.0
+oslo.config>=2.3.0 # Apache-2.0
+oslo.i18n>=1.5.0 # Apache-2.0
+oslo.policy>=0.5.0 # Apache-2.0
+oslo.serialization>=1.4.0 # Apache-2.0
+oslo.utils>=2.0.0 # Apache-2.0
+pyScss>=1.3.4 # MIT License
+python-ceilometerclient>=1.5.0
+python-cinderclient>=1.3.1
+python-glanceclient>=0.18.0
+python-heatclient>=0.3.0
+python-keystoneclient>=1.6.0
+python-neutronclient>=2.6.0
+python-novaclient>=2.28.1
+python-saharaclient>=0.10.0
+python-swiftclient>=2.2.0
+python-troveclient>=1.2.0
+pytz>=2013.6
+PyYAML>=3.1.0
+six>=1.9.0
+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-bootswatch>=3.3.5.3 # MIT 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-mdi==1.1.70.1 # SIL OPEN FONT LICENSE Version 1.1
+XStatic-Rickshaw>=1.5.0 # BSD License (prior)
+XStatic-roboto-fontface>=0.4.3.2 # Apache 2.0 License
+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
+
+horizon-contrib>=2015.7.6
+python-memcached
diff --git a/horizon/files/requirements/mitaka_contrail.txt b/horizon/files/requirements/mitaka_contrail.txt
new file mode 100644
index 0000000..57e9a31
--- /dev/null
+++ b/horizon/files/requirements/mitaka_contrail.txt
@@ -0,0 +1,76 @@
+# 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>=1.6
+# Horizon Core Requirements
+Babel>=1.3
+Django<1.9,>=1.8
+Pint>=0.5 # BSD
+django-babel>=0.4.0
+django-compressor>=1.4
+django-openstack-auth>=2.0.0
+django-pyscss>=2.0.2 # BSD License (2 clause)
+httplib2>=0.7.5
+iso8601>=0.1.9
+netaddr!=0.7.16,>=0.7.12
+oslo.concurrency>=2.3.0 # Apache-2.0
+oslo.config>=3.2.0 # Apache-2.0
+oslo.i18n>=1.5.0 # Apache-2.0
+oslo.policy>=0.5.0 # Apache-2.0
+oslo.serialization>=1.10.0 # Apache-2.0
+oslo.utils>=3.2.0 # Apache-2.0
+pyScss>=1.3.4 # MIT License
+python-ceilometerclient>=2.0.0
+python-cinderclient>=1.3.1
+python-glanceclient>=1.2.0
+python-heatclient>=0.6.0
+python-keystoneclient!=1.8.0,>=1.6.0
+python-neutronclient>=2.6.0
+python-novaclient!=2.33.0,>=2.29.0
+python-swiftclient>=2.2.0
+pytz>=2013.6
+PyYAML>=3.1.0
+six>=1.9.0
+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-bootswatch>=3.3.5.3 # MIT 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-mdi==1.1.70.1 # SIL OPEN FONT LICENSE Version 1.1
+XStatic-Rickshaw>=1.5.0 # BSD License (prior)
+XStatic-roboto-fontface>=0.4.3.2 # Apache 2.0 License
+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
+
+horizon-contrib>=2015.10.0
+
+#contrail
+argparse
+cliff>=1.6.0
+simplejson>=2.2.0
+python-memcached
+
+# metadata update needs
+functools32==3.2.3-2
+jsonpointer==1.10
\ No newline at end of file
diff --git a/horizon/files/requirements/mitaka_vanilla.txt b/horizon/files/requirements/mitaka_vanilla.txt
new file mode 100644
index 0000000..696615b
--- /dev/null
+++ b/horizon/files/requirements/mitaka_vanilla.txt
@@ -0,0 +1,70 @@
+# 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>=1.6
+# Horizon Core Requirements
+Babel>=1.3
+Django<1.9,>=1.8
+Pint>=0.5 # BSD
+django-babel>=0.4.0
+django-compressor>=1.4
+django-openstack-auth>=2.0.0
+django-pyscss>=2.0.2 # BSD License (2 clause)
+httplib2>=0.7.5
+iso8601>=0.1.9
+netaddr!=0.7.16,>=0.7.12
+oslo.concurrency>=2.3.0 # Apache-2.0
+oslo.config>=3.2.0 # Apache-2.0
+oslo.i18n>=1.5.0 # Apache-2.0
+oslo.policy>=0.5.0 # Apache-2.0
+oslo.serialization>=1.10.0 # Apache-2.0
+oslo.utils>=3.2.0 # Apache-2.0
+pyScss>=1.3.4 # MIT License
+python-ceilometerclient>=2.0.0
+python-cinderclient>=1.3.1
+python-glanceclient>=1.2.0
+python-heatclient>=0.6.0
+python-keystoneclient!=1.8.0,>=1.6.0
+python-neutronclient>=2.6.0
+python-novaclient!=2.33.0,>=2.29.0
+python-swiftclient>=2.2.0
+pytz>=2013.6
+PyYAML>=3.1.0
+six>=1.9.0
+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-bootswatch>=3.3.5.3 # MIT 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-mdi==1.1.70.1 # SIL OPEN FONT LICENSE Version 1.1
+XStatic-Rickshaw>=1.5.0 # BSD License (prior)
+XStatic-roboto-fontface>=0.4.3.2 # Apache 2.0 License
+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
+
+horizon-contrib>=2015.10.0
+
+# metadata update needs
+functools32==3.2.3-2
+jsonpointer==1.10
\ No newline at end of file
diff --git a/horizon/files/requirements/robotice_vanilla.txt b/horizon/files/requirements/robotice_vanilla.txt
new file mode 100644
index 0000000..84fea56
--- /dev/null
+++ b/horizon/files/requirements/robotice_vanilla.txt
@@ -0,0 +1,64 @@
+# PBR should always appear first
+pbr>=0.6,!=0.7,<1.0
+prettytable>=0.7.2
+stevedore>=1.2.0
+Babel>=1.3
+# Horizon Core Requirements
+Django>=1.4.2,<1.7
+django_compressor>=1.4
+django_openstack_auth>=1.1.7
+django-pyscss>=1.0.3 # BSD License (2 clause)
+eventlet>=0.15.1
+httplib2>=0.7.5
+iso8601>=0.1.9
+kombu>=2.5.0
+# Horizon Utility Requirements
+# for SECURE_KEY generation
+lockfile>=0.8
+netaddr>=0.7.12
+pyScss>=1.2.1,<1.3 # MIT License
+python-ceilometerclient>=1.0.6
+python-cinderclient>=1.1.0
+python-glanceclient>=0.14.0
+python-heatclient>=0.2.9
+python-keystoneclient>=0.10.0
+python-neutronclient>=2.3.6,<3
+python-novaclient>=2.18.0
+python-saharaclient>=0.7.3
+python-swiftclient>=2.2.0
+python-troveclient>=1.0.4
+pytz
+six>=1.7.0
+requests==2.1.0
+raven>=3.5.2
+gunicorn>=18.0
+oslo.config>=1.4.0 # Apache-2.0
+oslo.i18n>=1.0.0 # Apache-2.0
+oslo.serialization>=1.0.0 # Apache-2.0
+oslo.utils>=1.1.0 # Apache-2.0
+xstatic>=1.0.0 # MIT License
+xstatic-angular>=1.2.1.1 # MIT License
+xstatic-angular-cookies>=1.2.1.1 # MIT License
+xstatic-angular-mock>=1.2.1.1 # 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.1.0 # SIL OFL 1.1 License, MIT License
+xstatic-jasmine>=1.3.1.1 # 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.0.5b.0 # MIT License
+xstatic-jquery-ui>=1.10.1 # MIT License
+xstatic-jsencrypt>=2.0.0.2 # MIT License
+xstatic-qunit>=1.14.0.2 # MIT License
+xstatic-rickshaw>=1.5.0 # BSD License (prior)
+xstatic-spin>=1.2.5.2 # MIT License
+cryptography
+greenlet>=0.4.5
+django-appconf
+django-markitup==2.2.2
+xstatic-adminlte>=2.0.1.1
+django_image_proxy>=0.0.1
+django-bootstrap3-datetimepicker
\ No newline at end of file
diff --git a/horizon/files/sensu.conf b/horizon/files/sensu.conf
new file mode 100644
index 0000000..6f5cc00
--- /dev/null
+++ b/horizon/files/sensu.conf
@@ -0,0 +1,22 @@
+{%- from "linux/map.jinja" import network with context -%}
+{%- from "horizon/map.jinja" import server with context -%}
+
+{%- if server.app is defined %}
+
+{%- for app_name, app in server.app.iteritems() %}
+{%- set site = salt['pillar.get']('nginx:server:site:horizon_'+app_name) %}
+local_supervisor_server_service_horizon_{{ app_name }}.{{ network.fqdn }}:
+ command: "PATH=$PATH:/etc/sensu/plugins check_supervisor_proc.py -p horizon_{{ app_name }}"
+ interval: 60
+ occurrences: 1
+ subscribers:
+ - {{ network.fqdn|replace('.', '-') }}
+remote_horizon_login_{{ app_name }}.{{ site.host.name }}:
+ command: "PATH=$PATH:/usr/local/bin oschecks-check_horizon_login -E {{ site.host.name }} -U :::openstack.user::: -P :::openstack.password::: -c /tmp/check_horizon_{{ app_name }}.{{ site.host.name }}_cookieFile"
+ interval: 120
+ occurrences: 1
+ subscribers:
+ - remote-network
+{%- endfor %}
+
+{%- endif %}
diff --git a/horizon/files/supervisor.conf b/horizon/files/supervisor.conf
new file mode 100644
index 0000000..abf3fdd
--- /dev/null
+++ b/horizon/files/supervisor.conf
@@ -0,0 +1,14 @@
+{%- set service = salt['pillar.get']('supervisor:server:service:'+service_name) %}
+{%- set app = salt['pillar.get']('horizon:server:app:'+service.name) %}
+
+[program:{{ service_name }}]
+environment=PATH="/srv/horizon/bin"
+
+command=/srv/horizon/sites/{{ service.name }}/gunicorn_start
+
+stdout_logfile=/var/log/horizon/{{ service.name }}_app.log
+stderr_logfile=/var/log/horizon/{{ service.name }}_error.log
+
+user=horizon
+autostart=true
+autorestart=true
diff --git a/horizon/files/wsgi.py b/horizon/files/wsgi.py
new file mode 100644
index 0000000..88277bf
--- /dev/null
+++ b/horizon/files/wsgi.py
@@ -0,0 +1,41 @@
+
+import os
+import sys
+
+sys.stdout = sys.stderr
+
+{%- set app = salt['pillar.get']('horizon:server:app:'+app_name) %}
+
+import site
+
+from os.path import join
+
+#site.addsitedir('/srv/horizon/lib/python2.7/site-packages')
+
+path = '/srv/horizon'
+
+sys.path.append(join(path, 'sites', '{{ app_name }}', 'lib', 'python2.7', 'site-packages'))
+sys.path.append(join(path, 'sites', '{{ app_name }}', 'extra'))
+{%- if app.plugin is defined %}
+{%- for plugin_name, plugin in app.plugin.iteritems() %}
+sys.path.append(join(path, 'sites', '{{ app_name }}', 'plugins', '{{ plugin_name }}'))
+{%- endfor %}
+{%- endif %}
+
+import os
+#os.environ['PYTHON_EGG_CACHE'] = '/www/lostquery.com/mod_wsgi/egg-cache'
+
+os.environ['DJANGO_SETTINGS_MODULE'] = '{{ app.get('dashboard', 'openstack') }}_dashboard.settings'
+
+import django
+if django.VERSION < (1, 6):
+ from django.core.handlers.wsgi import WSGIHandler
+
+ application = WSGIHandler()
+else:
+ # From 1.4 wsgi support was improved and since 1.7 old style WSGI script
+ # causes AppRegistryNotReady exception
+ # https://docs.djangoproject.com/en/dev/releases/1.7/#wsgi-scripts
+ from django.core.wsgi import get_wsgi_application
+
+ application = get_wsgi_application()
diff --git a/horizon/init.sls b/horizon/init.sls
new file mode 100644
index 0000000..49430a2
--- /dev/null
+++ b/horizon/init.sls
@@ -0,0 +1,7 @@
+
+{%- if pillar.horizon is defined %}
+include:
+{%- if pillar.horizon.server is defined %}
+- horizon.server
+{%- endif %}
+{%- endif %}
diff --git a/horizon/map.jinja b/horizon/map.jinja
new file mode 100644
index 0000000..e7593f8
--- /dev/null
+++ b/horizon/map.jinja
@@ -0,0 +1,34 @@
+{% set server = salt['grains.filter_by']({
+ 'Debian': {
+ 'pkgs': ['apache2', 'openstack-dashboard', 'python-lesscpy', 'python-memcache'],
+ 'pkgs_multi': ['python-memcache', 'python-psycopg2', 'python-imaging',
+ 'python-docutils', 'python-simplejson', 'build-essential',
+ 'libxslt1-dev', 'libxml2-dev', 'libffi-dev', 'libssl-dev',
+ 'gettext', 'python-lesscpy'],
+ 'ssl_pkgs': ['openstack-dashboard'],
+ 'service': 'apache2',
+ 'config': '/etc/openstack-dashboard/local_settings.py',
+ 'apache_config': '/etc/apache2/conf-available/openstack-dashboard.conf',
+ 'certs_dir': '/etc/ssl/certs',
+ 'private_dir': '/etc/ssl/private',
+ 'port_config_file': '/etc/apache2/ports.conf',
+ 'port_config_template': 'salt://horizon/files/ports.conf',
+ 'cache': {'host': '127.0.0.1', 'port': 11211}
+ },
+ 'RedHat': {
+ 'pkgs': ['httpd', 'openstack-dashboard', 'python-lesscpy', 'python-memcached'],
+ 'pkgs_multi': ['python-memcached', 'python-psycopg2', 'python-pillow',
+ 'python-docutils', 'python-simplejson', 'libxslt-devel', 'gcc',
+ 'libxml2-devel', 'libffi-devel', 'openssl-devel',
+ 'gettext', 'python-lesscpy'],
+ 'ssl_pkgs': ['mod_ssl'],
+ 'service': 'httpd',
+ 'config': '/etc/openstack-dashboard/local_settings',
+ 'apache_config': '/etc/httpd/conf.d/openstack-dashboard.conf',
+ 'certs_dir': '/etc/pki/tls/certs',
+ 'private_dir': '/etc/pki/tls/private',
+ 'port_config_file': '/etc/httpd/conf/httpd.conf',
+ 'port_config_template': 'salt://horizon/files/httpd.conf',
+ 'cache': {'host': '127.0.0.1', 'port': 11211}
+ },
+}, merge=salt['pillar.get']('horizon:server')) %}
diff --git a/horizon/meta/sensu.yml b/horizon/meta/sensu.yml
new file mode 100644
index 0000000..ce2166c
--- /dev/null
+++ b/horizon/meta/sensu.yml
@@ -0,0 +1,32 @@
+{%- from "linux/map.jinja" import network with context -%}
+{%- from "horizon/map.jinja" import server with context -%}
+{%- if server.app is defined %}
+check:
+{%- for app_name, app in server.app.iteritems() %}
+{%- set site = salt['pillar.get']('nginx:server:site:horizon_'+app_name) %}
+ local_supervisor_server_service_horizon_{{ app_name }}.{{ network.fqdn }}:
+ command: "PATH=$PATH:/etc/sensu/plugins check_supervisor_proc.py -p horizon_{{ app_name }}"
+ interval: 60
+ occurrences: 1
+ subscribers:
+ - {{ network.fqdn|replace('.', '-') }}
+ remote_horizon_login_{{ app_name }}.{{ site.host.name }}:
+ command: "PATH=$PATH:/usr/local/bin oschecks-check_horizon_login -E {{ site.host.name }} -U :::openstack.user::: -P :::openstack.password::: -c /tmp/check_horizon_{{ app_name }}.{{ site.host.name }}_cookieFile"
+ interval: 120
+ occurrences: 1
+ subscribers:
+ - remote-network
+{%- endfor %}
+{%- else %}
+{%- if server.host is defined %}
+check:
+ remote_horizon_login_{{ server.host.name }}_{{ server.host.get('port', 80) }}:
+ command: "PATH=$PATH:/usr/local/bin oschecks-check_horizon_login -E {{ server.host.name }} -U :::openstack.user::: -P :::openstack.password::: -c /tmp/check_horizon_{{ server.host.name }}_cookieFile"
+ interval: 120
+ occurrences: 1
+ subscribers:
+ - remote-network
+{%- else %}
+check: {}
+{%- endif %}
+{%- endif %}
diff --git a/horizon/meta/sphinx.yml b/horizon/meta/sphinx.yml
new file mode 100644
index 0000000..b71bf2d
--- /dev/null
+++ b/horizon/meta/sphinx.yml
@@ -0,0 +1,32 @@
+{%- from "horizon/map.jinja" import server with context %}
+doc:
+ name: Horizon
+ description: Horizon is the canonical implementation of OpenStacks Dashboard, which provides a web based user interface to OpenStack services including Nova, Swift, Keystone, etc.
+ role:
+ server:
+ name: server
+ {%- if pillar.horizon.server is defined %}
+ endpoint:
+ {%- for app_name, app in server.get('app', {}).iteritems() %}
+ horizon_{{ app_name }}:
+ name: {{ app_name }}
+ type: horizon
+ address: "http://{{ app.bind.address }}:{{ app.bind.port }}/"
+ protocol: http
+ {%- endfor %}
+ param:
+ bind:
+ value: {{ server.bind.address }}:{{ server.bind.port }}
+ version:
+ name: "Version"
+ value: {{ server.version }}
+ identity_host:
+ name: "Identity service"
+ value: {{ server.identity.host }}:{{ server.identity.port }}
+ packages:
+ value: |
+ {%- for pkg in server.pkgs %}
+ {%- set pkg_version = "dpkg -l "+pkg+" | grep "+pkg+" | awk '{print $3}'" %}
+ * {{ pkg }}: {{ salt['cmd.run'](pkg_version) }}
+ {%- endfor %}
+ {%- endif %}
\ No newline at end of file
diff --git a/horizon/server/init.sls b/horizon/server/init.sls
new file mode 100644
index 0000000..8b77234
--- /dev/null
+++ b/horizon/server/init.sls
@@ -0,0 +1,15 @@
+include:
+{%- if pillar.horizon.server.app is defined %}
+{# uglier way, for development #}
+- horizon.server.multi.service_git
+- horizon.server.multi.site
+{%- else %}
+{# production way #}
+- horizon.server.service
+{%- if pillar.horizon.server.plugin is defined %}
+- horizon.server.plugin
+{%- endif %}
+{%- if pillar.horizon.server.ssl is defined %}
+- horizon.server.ssl
+{%- endif %}
+{%- endif %}
diff --git a/horizon/server/multi/init.sls b/horizon/server/multi/init.sls
new file mode 100644
index 0000000..63fa6f4
--- /dev/null
+++ b/horizon/server/multi/init.sls
@@ -0,0 +1,7 @@
+{%- from "horizon/map.jinja" import server with context %}
+{%- if server.enabled %}
+
+include:
+- horizon.server.multi.service_git
+
+{%- endif %}
diff --git a/horizon/server/multi/service_git.sls b/horizon/server/multi/service_git.sls
new file mode 100644
index 0000000..8367190
--- /dev/null
+++ b/horizon/server/multi/service_git.sls
@@ -0,0 +1,15 @@
+{%- from "horizon/map.jinja" import server with context %}
+{%- if server.enabled %}
+
+include:
+- git
+- python
+
+horizon_packages:
+ pkg.installed:
+ - names: {{ server.pkgs_multi }}
+ - require:
+ - pkg: python_packages
+
+{%- endif %}
+
diff --git a/horizon/server/multi/site.sls b/horizon/server/multi/site.sls
new file mode 100644
index 0000000..178d5fb
--- /dev/null
+++ b/horizon/server/multi/site.sls
@@ -0,0 +1,346 @@
+{%- from "horizon/map.jinja" import server with context %}
+{%- if server.enabled %}
+
+include:
+- git
+
+horizon_user:
+ user.present:
+ - name: horizon
+ - system: True
+ - home: /srv/horizon
+
+/var/log/horizon:
+ file.directory:
+ - mode: 770
+ - user: horizon
+ - group: root
+ - require:
+ - user: horizon_user
+
+/srv/horizon/sites:
+ file.directory:
+ - makedirs: true
+
+{%- for app_name, app in server.app.iteritems() %}
+
+{%- if app.get('dashboard', 'openstack') in ['openstack', 'helpdesk'] %}
+{%- if app.get('version', 'juno') in ['juno', 'kilo', 'liberty', 'mitaka'] %}
+{%- set config_file = "/srv/horizon/sites/"+app_name+"/lib/python" + pillar.python.environment.get("version", "2.7") + "/site-packages/openstack_dashboard/local/local_settings.py" %}
+{%- else %}
+{%- set config_file = "/srv/horizon/sites/"+app_name+"/extra/openstack_dashboard/local/local_settings.py" %}
+{%- endif %}
+{%- elif app.get('dashboard', 'openstack') == 'csb' %}
+{%- set config_file = "/srv/horizon/sites/"+app_name+"/plugins/csb_dashboard/csb_dashboard/local/local_settings.py" %}
+{%- elif app.get('dashboard', 'openstack') == 'robotice' %}
+{%- set config_file = "/srv/horizon/sites/"+app_name+"/plugins/robotice_dashboard/robotice_dashboard/local/local_settings.py" %}
+{%- endif %}
+
+{%- if app.plugin.contrail is defined %}
+{%- set requirements = "contrail" %}
+{%- else %}
+{%- set requirements = "vanilla" %}
+{%- endif %}
+
+/srv/horizon/sites/{{ app_name }}:
+ virtualenv.manage:
+ - system_site_packages: False
+ - requirements: salt://horizon/files/requirements/{{ app.version }}_{{ requirements }}.txt
+ - require:
+ - file: /srv/horizon/sites
+ - pkg: horizon_packages
+
+{{ app_name }}_{{ app.source.address }}:
+ git.latest:
+ - name: {{ app.source.address }}
+ - target: /srv/horizon/sites/{{ app_name }}/extra
+ - rev: {{ app.source.revision }}
+ - depth: 1
+ - submodules: True
+ - require:
+ - virtualenv: /srv/horizon/sites/{{ app_name }}
+ - pkg: git_packages
+
+horizon_{{ app_name }}_dirs:
+ file.directory:
+ - names:
+ - /srv/horizon/sites/{{ app_name }}/media
+ - /var/log/horizon
+ - mode: 777
+ - user: horizon
+ - group: horizon
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+
+horizon_{{ app_name }}_logs:
+ file.managed:
+ - names:
+ - /var/log/horizon/{{ app_name }}_app.log
+ - /var/log/horizon/{{ app_name }}_error.log
+ - /var/log/horizon/{{ app_name }}_gunicorn.log
+ - /var/log/horizon/{{ app_name }}_horizon.log
+ - user: horizon
+ - group: horizon
+ - replace: False
+ - require:
+ - file: horizon_{{ app_name }}_dirs
+
+{%- if app.get('version', 'juno') in ['juno', 'kilo', 'helpdesk', 'liberty', 'mitaka'] %}
+
+horizon_setup_{{ app_name }}_horizon:
+ cmd.run:
+ - names:
+ - source /srv/horizon/sites/{{ app_name }}/bin/activate; python setup.py install
+ - cwd: /srv/horizon/sites/{{ app_name }}/extra
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+ - require_in:
+ - file: horizon_{{ app_name }}_config
+
+{%- if app.get('api_versions', {}).identity is defined %}
+{%- if app.get('api_versions', {}).identity == '3' %}
+
+horizon_{{ app_name }}_config:
+ file.managed:
+ - name: /srv/horizon/sites/{{ app_name }}/lib/python{{ pillar.python.environment.get("version", "2.7") }}/site-packages/openstack_dashboard/conf/keystone_policy.json
+ - source: salt://horizon/files/policy/{{ app.version }}-keystone-v3.json
+ - require:
+ - cmd: horizon_setup_{{ app_name }}_horizon
+
+{%- endif %}
+{%- endif %}
+
+{%- endif %}
+
+{%- if app.get('version', 'juno') in ['kilo', 'helpdesk', 'liberty', 'mitaka'] %}
+
+/srv/horizon/sites/{{ app_name }}/static:
+ file.symlink:
+ - target: /srv/horizon/sites/{{ app_name }}/local/lib/python2.7/site-packages/static
+ - mode: 777
+ - user: root
+ - group: root
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+
+horizon_{{ app_name }}_config:
+ file.managed:
+ - name: /srv/horizon/sites/{{ app_name }}/lib/python{{ pillar.python.environment.get("version", "2.7") }}/site-packages/openstack_dashboard/local/local_settings.py
+ - source: salt://horizon/files/local_settings/{{ app.version }}_settings.py
+ - template: jinja
+ - mode: 644
+ - user: root
+ - group: root
+ - defaults:
+ app_name: {{ app_name }}
+ - require_in:
+ - file: /srv/horizon/sites/{{ app_name }}/manage.py
+
+{%- else %}
+
+/srv/horizon/sites/{{ app_name }}/static:
+ file.directory:
+ - mode: 777
+ - user: root
+ - group: root
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+
+horizon_{{ app_name }}_config:
+ file.managed:
+ - name: {{ config_file }}
+ - source: salt://horizon/files/local_settings/{{ app.version }}_settings.py
+ - template: jinja
+ - mode: 644
+ - user: root
+ - group: root
+ - defaults:
+ app_name: {{ app_name }}
+ - require_in:
+ - file: /srv/horizon/sites/{{ app_name }}/manage.py
+
+{%- endif %}
+
+/srv/horizon/sites/{{ app_name }}/manage.py:
+ file.managed:
+ - source: salt://horizon/files/manage.py
+ - template: jinja
+ - mode: 777
+ - user: root
+ - group: root
+ - defaults:
+ app_name: {{ app_name }}
+
+/srv/horizon/sites/{{ app_name }}/wsgi.py:
+ file.managed:
+ - source: salt://horizon/files/wsgi.py
+ - template: jinja
+ - mode: 644
+ - user: root
+ - group: root
+ - defaults:
+ app_name: {{ app_name }}
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+
+{%- if app.plugin.merlin_panels is defined %}
+
+/srv/horizon/sites/{{ app_name }}/database.db:
+ file.managed:
+ - mode: 666
+ - user: horizon
+ - group: horizon
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+
+{%- endif %}
+
+{#
+{%- for dashboard_name, dashboard in app.plugin.iteritems() %}
+{%- endfor %}
+#}
+
+{%- if app.plugin is defined %}
+
+/srv/horizon/sites/{{ app_name }}/plugins:
+ file.directory:
+ - makedirs: True
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+
+{%- for dashboard_name, dashboard in app.get('dashboards', {}).iteritems() %}
+
+{%- if app.get('version', 'juno') in ['kilo', 'helpdesk', 'liberty', 'mitaka'] %}
+
+horizon_{{ app_name }}_{{ dashboard_name }}_config:
+ file.managed:
+ - name: /srv/horizon/sites/{{ app_name }}/lib/python{{ pillar.python.environment.get("version", "2.7") }}/site-packages/openstack_dashboard/enabled/_{{ dashboard.get('order', 70) }}_{{ dashboard_name }}.py
+ - source: salt://horizon/files/enabled/{{ dashboard_name }}.py
+ - template: jinja
+ - mode: 644
+ - user: root
+ - group: root
+ - defaults:
+ app_name: {{ app_name }}
+ enabled: {{ dashboard.enabled }}
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+
+{%- endif %}
+
+{%- endfor %}
+
+
+{%- for plugin_name, plugin in app.plugin.iteritems() %}
+
+{%- if app.get('version', 'juno') in ['kilo', 'helpdesk', 'liberty', 'mitaka'] %}
+
+horizon_{{ app_name }}_{{ plugin_name }}_config:
+ file.managed:
+ - name: /srv/horizon/sites/{{ app_name }}/lib/python{{ pillar.python.environment.get("version", "2.7") }}/site-packages/openstack_dashboard/local/enabled/_{{ plugin.get('
+ ', 60) }}_{{ plugin_name }}.py
+ - source: salt://horizon/files/enabled/{{ plugin_name }}.py
+ - template: jinja
+ - mode: 644
+ - user: root
+ - group: root
+ - defaults:
+ app_name: {{ app_name }}
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+
+{%- endif %}
+
+{{ app_name }}_{{ plugin_name }}:
+ {{ plugin.source.engine }}.latest:
+ - name: {{ plugin.source.address }}
+ - target: /srv/horizon/sites/{{ app_name }}/plugins/{{ plugin_name }}
+ - rev: {{ plugin.source.revision }}
+ - submodules: True
+ - require:
+ - file: /srv/horizon/sites/{{ app_name }}/plugins
+ - require_in:
+ - cmd: horizon_setup_{{ app_name }}
+
+{%- if plugin_name == "contrail" and app.get("version", "juno") in ["juno", "kilo", 'helpdesk', 'liberty', 'mitaka'] %}
+
+fix_contrail_{{ app_name }}:
+ cmd.run:
+ - name: source /srv/horizon/sites/{{ app_name }}/bin/activate; pip install git+https://github.com/Juniper/python-neutronclient.git@contrail/juno#egg=python-neutronclient --upgrade --no-deps
+ - cwd: /srv/horizon/sites/{{ app_name }}
+
+{%- endif %}
+
+{%- if plugin_name == "horizon_theme" and app.get("version", "juno") in ["kilo", 'helpdesk'] %}
+
+/srv/horizon/sites/{{ app_name }}/local/lib/python2.7/site-packages/openstack_dashboard/dashboards/theme:
+ file.symlink:
+ - target: /srv/horizon/sites/{{ app_name }}/plugins/{{ plugin_name }}/horizon_theme/dashboards/theme
+ - user: root
+ - group: root
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+
+/srv/horizon/sites/{{ app_name }}/local/lib/python2.7/site-packages/openstack_dashboard/static/themes/{{ plugin.theme_name }}:
+ file.symlink:
+ - target: /srv/horizon/sites/{{ app_name }}/plugins/{{ plugin_name }}/horizon_theme/dashboards/theme/static/themes/{{ plugin.theme_name }}
+ - user: root
+ - group: root
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+
+{%- elif plugin_name == "horizon_theme" and app.get("version", "liberty") in ['liberty', 'mitaka'] %}
+
+/srv/horizon/sites/{{ app_name }}/local/lib/python2.7/site-packages/openstack_dashboard/dashboards/theme:
+ file.symlink:
+ - target: /srv/horizon/sites/{{ app_name }}/plugins/{{ plugin_name }}/horizon_theme/dashboards/theme
+ - user: root
+ - group: root
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+
+/srv/horizon/sites/{{ app_name }}/local/lib/python2.7/site-packages/openstack_dashboard/themes/{{ plugin.theme_name }}:
+ file.symlink:
+ - target: /srv/horizon/sites/{{ app_name }}/plugins/{{ plugin_name }}/horizon_theme/static/{{ plugin.theme_name }}
+ - user: root
+ - group: root
+ - require:
+ - git: {{ app_name }}_{{ app.source.address }}
+
+{%- endif %}
+
+{%- endfor %}
+
+{%- endif %}
+
+horizon_setup_{{ app_name }}:
+ cmd.run:
+ - names:
+ - source /srv/horizon/sites/{{ app_name }}/bin/activate; python manage.py collectstatic --noinput; python manage.py compress --force
+ {%- if app.plugin.merlin_panels is defined %}
+ - source /srv/horizon/sites/{{ app_name }}/bin/activate; python manage.py syncdb --noinput
+ {%- endif %}
+ - chown horizon:horizon static -R
+ - cwd: /srv/horizon/sites/{{ app_name }}
+ - require:
+ - file: /srv/horizon/sites/{{ app_name }}/manage.py
+ - git: {{ app_name }}_{{ app.source.address }}
+ {%- if app.get('version', 'juno') in ['juno'] %}
+ - cmd: horizon_setup_{{ app_name }}_horizon
+ {%- endif %}
+
+/srv/horizon/sites/{{ app_name }}/gunicorn_start:
+ file.managed:
+ - source: salt://horizon/files/gunicorn_start
+ - template: jinja
+ - mode: 777
+ - user: horizon
+ - group: horizon
+ - defaults:
+ app_name: {{ app_name }}
+ - require:
+ - cmd: horizon_setup_{{ app_name }}
+
+{%- endfor %}
+
+{%- endif %}
diff --git a/horizon/server/plugin.sls b/horizon/server/plugin.sls
new file mode 100644
index 0000000..f2c7caa
--- /dev/null
+++ b/horizon/server/plugin.sls
@@ -0,0 +1,32 @@
+{%- from "horizon/map.jinja" import server with context %}
+{%- if server.plugin is defined %}
+
+{%- if server.get('plugin', {}).horizon_theme is defined %}
+
+horizon_horizon_theme_package:
+ pkg.installed:
+ - name: {{ server.plugin.horizon_theme.source.name }}
+ - watch_in:
+ - service: horizon_services
+
+{%- endif %}
+
+{%- for plugin_name, plugin in server.get('plugin', {}).iteritems() %}
+
+{%- if plugin_name != "horizon_theme" %}
+
+horizon_{{ plugin_name }}_package:
+ pkg.installed:
+ - name: {{ plugin.source.name }}
+ {%- if server.get('plugin', {}).horizon_theme is defined %}
+ - require:
+ - pkg: horizon_horizon_theme_package
+ {%- endif %}
+ - watch_in:
+ - service: horizon_services
+
+{%- endif %}
+
+{%- endfor %}
+
+{%- endif %}
\ No newline at end of file
diff --git a/horizon/server/service.sls b/horizon/server/service.sls
new file mode 100644
index 0000000..20e121a
--- /dev/null
+++ b/horizon/server/service.sls
@@ -0,0 +1,76 @@
+{%- from "horizon/map.jinja" import server with context %}
+{%- if server.enabled %}
+
+horizon_packages:
+ pkg.installed:
+ - names: {{ server.pkgs }}
+
+horizon_config:
+ file.managed:
+ - name: {{ server.config }}
+ - source: salt://horizon/files/local_settings/{{ server.version }}_settings.py
+ - template: jinja
+ - mode: 644
+ - user: root
+ - group: root
+ - require:
+ - pkg: horizon_packages
+
+horizon_apache_port_config:
+ file.managed:
+ - name: {{ server.port_config_file }}
+ - source: {{ server.port_config_template }}
+ - template: jinja
+ - mode: 644
+ - user: root
+ - group: root
+ - require_in:
+ - service: horizon_services
+ - require:
+ - pkg: horizon_packages
+
+horizon_apache_config:
+ file.managed:
+ - name: {{ server.apache_config }}
+ - source: salt://horizon/files/openstack-dashboard.conf.{{ grains.os_family }}
+ - template: jinja
+ - mode: 644
+ - user: root
+ - group: root
+ - require:
+ - pkg: horizon_packages
+
+/etc/apache2/conf-enabled/openstack-dashboard.conf:
+ file.symlink:
+ - target: /etc/apache2/conf-available/openstack-dashboard.conf
+
+apache_enable_wsgi:
+ apache_module.enable:
+ - name: wsgi
+
+horizon_services:
+ service.running:
+ - name: {{ server.service }}
+ - enable: true
+ - watch:
+ - file: horizon_config
+ - file: horizon_apache_config
+ - file: horizon_log_file
+
+horizon_log_dir:
+ file.directory:
+ - name: /var/log/horizon
+ - user: horizon
+ - group: adm
+ - mode: 750
+
+horizon_log_file:
+ file.managed:
+ - name: /var/log/horizon/horizon.log
+ - user: horizon
+ - group: adm
+ - mode: 640
+ - require:
+ - file: horizon_log_dir
+
+{%- endif %}
diff --git a/horizon/server/ssl.sls b/horizon/server/ssl.sls
new file mode 100644
index 0000000..7cf2a36
--- /dev/null
+++ b/horizon/server/ssl.sls
@@ -0,0 +1,61 @@
+{%- from "horizon/map.jinja" import server with context %}
+{%- if server.ssl.enabled %}
+
+horizon_ssl_packages:
+ pkg.installed:
+ - names: {{ server.ssl_pkgs }}
+ - watch_in:
+ - file: horizon_config
+
+{% if grains.os_family == 'RedHat' %}
+
+horizon_apache_ssl_config:
+ file.managed:
+ - name: /etc/httpd/conf.d/ssl.conf
+ - source: salt://horizon/conf/ssl.conf.{{ grains.os_family }}
+ - template: jinja
+ - mode: 644
+ - user: root
+ - group: root
+ - require:
+ - pkg: horizon_packages
+
+{% endif %}
+
+{{ server.certs_dir }}/{{ server.host.name }}.crt:
+ file.managed:
+ {%- if server.cert is defined %}
+ - contents_pillar: horizon:server:cert
+ {%- else %}
+ - source: salt://pki/{{ server.ssl.authority }}/certs/{{ server.host.name }}.cert.pem
+ {%- endif %}
+ - require:
+ - pkg: horizon_packages
+ - require_in:
+ - service: horizon_services
+
+{{ server.private_dir }}/{{ server.host.name }}.key:
+ file.managed:
+ {%- if server.key is defined %}
+ - contents_pillar: horizon:server:key
+ {%- else %}
+ - source: salt://pki/{{ server.ssl.authority }}/certs/{{ server.host.name }}.key.pem
+ {%- endif %}
+ - require:
+ - pkg: horizon_packages
+ - require_in:
+ - service: horizon_services
+
+{{ server.certs_dir }}/{{ server.ssl.authority }}-chain.crt:
+ file.managed:
+ {%- if server.chain is defined %}
+ - contents_pillar: horizon:server:chain
+ {%- else %}
+ - source: salt://pki/{{ server.ssl.authority }}/{{ server.ssl.authority }}-chain.cert.pem
+ {%- endif %}
+ - require:
+ - pkg: horizon_packages
+ - require_in:
+ - service: horizon_services
+
+{%- endif %}
\ No newline at end of file
diff --git a/metadata.yml b/metadata.yml
new file mode 100644
index 0000000..e643fae
--- /dev/null
+++ b/metadata.yml
@@ -0,0 +1,3 @@
+name: "horizon"
+version: "2016.4.1"
+source: "https://github.com/openstack/salt-formula-horizon"
diff --git a/metadata/service/server/cluster.yml b/metadata/service/server/cluster.yml
new file mode 100644
index 0000000..c718ef1
--- /dev/null
+++ b/metadata/service/server/cluster.yml
@@ -0,0 +1,56 @@
+applications:
+- horizon
+classes:
+- service.horizon.support
+parameters:
+ _param:
+ horizon_version: kilo
+ horizon_api_version: 3
+ horizon:
+ server:
+ enabled: true
+ version: ${_param:horizon_version}
+ secret_key: ${_param:horizon_secret_key}
+ session_timeout: 43200
+ wsgi:
+ processes: 3
+ threads: 10
+ bind:
+ address: ${_param:cluster_local_address}
+ port: 80
+ cache:
+ engine: memcached
+ prefix: 'CACHE_HORIZON'
+ members:
+ - host: ${_param:cluster_node01_address}
+ port: 11211
+ - host: ${_param:cluster_node02_address}
+ port: 11211
+ - host: ${_param:cluster_node03_address}
+ port: 11211
+ identity:
+ engine: keystone
+ host: ${_param:cluster_vip_address}
+ port: 5000
+ api_version: 2
+ haproxy:
+ proxy:
+ listens:
+ - name: horizon
+ type: horizon
+ binds:
+ - address: ${_param:cluster_vip_address}
+ port: 80
+ servers:
+ - name: ctl01
+ host: ${_param:cluster_node01_address}
+ port: 80
+ params: cookie ctl01 check inter 2000 fall 3
+ - name: ctl02
+ host: ${_param:cluster_node02_address}
+ port: 80
+ params: cookie ctl02 check inter 2000 fall 3
+ - name: ctl03
+ host: ${_param:cluster_node03_address}
+ port: 80
+ params: cookie ctl03 check inter 2000 fall 3
diff --git a/metadata/service/server/multi.yml b/metadata/service/server/multi.yml
new file mode 100644
index 0000000..627096c
--- /dev/null
+++ b/metadata/service/server/multi.yml
@@ -0,0 +1,6 @@
+applications:
+- horizon
+parameters:
+ horizon:
+ server:
+ enabled: true
diff --git a/metadata/service/server/single.yml b/metadata/service/server/single.yml
new file mode 100644
index 0000000..f49b9d6
--- /dev/null
+++ b/metadata/service/server/single.yml
@@ -0,0 +1,36 @@
+applications:
+- horizon
+classes:
+- service.horizon.support
+parameters:
+ _param:
+ horizon_version: liberty
+ horizon_identity_host: localhost
+ horizon_identity_version: 3
+ horizon_identity_encryption: none
+ horizon:
+ server:
+ enabled: true
+ version: ${_param:horizon_version}
+ secret_key: ${_param:horizon_secret_key}
+ session_timeout: 43200
+ bind:
+ address: ${_param:single_address}
+ port: 80
+ wsgi:
+ processes: 3
+ threads: 10
+ mail:
+ engine: dummy
+ cache:
+ engine: memcached
+ prefix: 'CACHE_HORIZON'
+ members:
+ - host: ${_param:single_address}
+ port: 11211
+ identity:
+ engine: keystone
+ port: 5000
+ host: ${_param:horizon_identity_host}
+ encryption: ${_param:horizon_identity_encryption}
+ api_version: ${_param:horizon_identity_version}
diff --git a/metadata/service/support.yml b/metadata/service/support.yml
new file mode 100644
index 0000000..2ebbaee
--- /dev/null
+++ b/metadata/service/support.yml
@@ -0,0 +1,11 @@
+parameters:
+ horizon:
+ _support:
+ collectd:
+ enabled: false
+ heka:
+ enabled: false
+ sensu:
+ enabled: true
+ sphinx:
+ enabled: true
diff --git a/other-requirements.txt b/other-requirements.txt
new file mode 100644
index 0000000..ba84cc5
--- /dev/null
+++ b/other-requirements.txt
@@ -0,0 +1 @@
+python-yaml
diff --git a/tests/pillar/cluster.sls b/tests/pillar/cluster.sls
new file mode 100644
index 0000000..3eb9909
--- /dev/null
+++ b/tests/pillar/cluster.sls
@@ -0,0 +1,48 @@
+horizon:
+ server:
+ enabled: true
+ version: liberty
+ secret_key: secret
+ session_timeout: 43200
+ wsgi:
+ processes: 3
+ threads: 10
+ bind:
+ address: 127.0.0.1
+ port: 80
+ cache:
+ engine: memcached
+ prefix: 'CACHE_HORIZON'
+ members:
+ - host: 127.0.0.1
+ port: 11211
+ - host: 127.0.0.1
+ port: 11211
+ - host: 127.0.0.1
+ port: 11211
+ identity:
+ engine: keystone
+ host: 127.0.0.1
+ port: 5000
+ api_version: 2
+haproxy:
+ proxy:
+ listens:
+ - name: horizon
+ type: horizon
+ binds:
+ - address: 127.0.0.1
+ port: 80
+ servers:
+ - name: ctl01
+ host: 127.0.0.1
+ port: 80
+ params: cookie ctl01 check inter 2000 fall 3
+ - name: ctl02
+ host: 127.0.0.1
+ port: 80
+ params: cookie ctl02 check inter 2000 fall 3
+ - name: ctl03
+ host: 127.0.0.1
+ port: 80
+ params: cookie ctl03 check inter 2000 fall 3
\ No newline at end of file
diff --git a/tests/pillar/single.sls b/tests/pillar/single.sls
new file mode 100644
index 0000000..827cd88
--- /dev/null
+++ b/tests/pillar/single.sls
@@ -0,0 +1,26 @@
+horizon:
+ server:
+ enabled: true
+ version: liberty
+ secret_key: secret
+ session_timeout: 43200
+ bind:
+ address: 127.0.0.1
+ port: 80
+ wsgi:
+ processes: 3
+ threads: 10
+ mail:
+ engine: dummy
+ cache:
+ engine: memcached
+ prefix: 'CACHE_HORIZON'
+ members:
+ - host: 127.0.0.1
+ port: 11211
+ identity:
+ engine: keystone
+ port: 5000
+ host: 127.0.0.1
+ encryption: encryption
+ api_version: 2
\ No newline at end of file
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
new file mode 100755
index 0000000..3f42101
--- /dev/null
+++ b/tests/run_tests.sh
@@ -0,0 +1,162 @@
+#!/usr/bin/env bash
+
+set -e
+[ -n "$DEBUG" ] && set -x
+
+CURDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+METADATA=${CURDIR}/../metadata.yml
+FORMULA_NAME=$(cat $METADATA | python -c "import sys,yaml; print yaml.load(sys.stdin)['name']")
+
+## Overrideable parameters
+PILLARDIR=${PILLARDIR:-${CURDIR}/pillar}
+BUILDDIR=${BUILDDIR:-${CURDIR}/build}
+VENV_DIR=${VENV_DIR:-${BUILDDIR}/virtualenv}
+DEPSDIR=${BUILDDIR}/deps
+
+SALT_FILE_DIR=${SALT_FILE_DIR:-${BUILDDIR}/file_root}
+SALT_PILLAR_DIR=${SALT_PILLAR_DIR:-${BUILDDIR}/pillar_root}
+SALT_CONFIG_DIR=${SALT_CONFIG_DIR:-${BUILDDIR}/salt}
+SALT_CACHE_DIR=${SALT_CACHE_DIR:-${SALT_CONFIG_DIR}/cache}
+
+SALT_OPTS="${SALT_OPTS} --retcode-passthrough --local -c ${SALT_CONFIG_DIR}"
+
+if [ "x${SALT_VERSION}" != "x" ]; then
+ PIP_SALT_VERSION="==${SALT_VERSION}"
+fi
+
+## Functions
+log_info() {
+ echo "[INFO] $*"
+}
+
+log_err() {
+ echo "[ERROR] $*" >&2
+}
+
+setup_virtualenv() {
+ log_info "Setting up Python virtualenv"
+ virtualenv $VENV_DIR
+ source ${VENV_DIR}/bin/activate
+ pip install salt${PIP_SALT_VERSION}
+}
+
+setup_pillar() {
+ [ ! -d ${SALT_PILLAR_DIR} ] && mkdir -p ${SALT_PILLAR_DIR}
+ echo "base:" > ${SALT_PILLAR_DIR}/top.sls
+ for pillar in ${PILLARDIR}/*; do
+ state_name=$(basename ${pillar%.sls})
+ echo -e " ${state_name}:\n - ${state_name}" >> ${SALT_PILLAR_DIR}/top.sls
+ done
+}
+
+setup_salt() {
+ [ ! -d ${SALT_FILE_DIR} ] && mkdir -p ${SALT_FILE_DIR}
+ [ ! -d ${SALT_CONFIG_DIR} ] && mkdir -p ${SALT_CONFIG_DIR}
+ [ ! -d ${SALT_CACHE_DIR} ] && mkdir -p ${SALT_CACHE_DIR}
+
+ echo "base:" > ${SALT_FILE_DIR}/top.sls
+ for pillar in ${PILLARDIR}/*.sls; do
+ state_name=$(basename ${pillar%.sls})
+ echo -e " ${state_name}:\n - ${FORMULA_NAME}" >> ${SALT_FILE_DIR}/top.sls
+ done
+
+ cat << EOF > ${SALT_CONFIG_DIR}/minion
+file_client: local
+cachedir: ${SALT_CACHE_DIR}
+verify_env: False
+
+file_roots:
+ base:
+ - ${SALT_FILE_DIR}
+ - ${CURDIR}/..
+ - /usr/share/salt-formulas/env
+
+pillar_roots:
+ base:
+ - ${SALT_PILLAR_DIR}
+ - ${PILLARDIR}
+EOF
+}
+
+fetch_dependency() {
+ dep_name="$(echo $1|cut -d : -f 1)"
+ dep_source="$(echo $1|cut -d : -f 2-)"
+ dep_root="${DEPSDIR}/$(basename $dep_source .git)"
+ dep_metadata="${dep_root}/metadata.yml"
+
+ [ -d /usr/share/salt-formulas/env/${dep_name} ] && log_info "Dependency $dep_name already present in system-wide salt env" && return 0
+ [ -d $dep_root ] && log_info "Dependency $dep_name already fetched" && return 0
+
+ log_info "Fetching dependency $dep_name"
+ [ ! -d ${DEPSDIR} ] && mkdir -p ${DEPSDIR}
+ git clone $dep_source ${DEPSDIR}/$(basename $dep_source .git)
+ ln -s ${dep_root}/${dep_name} ${SALT_FILE_DIR}/${dep_name}
+
+ METADATA="${dep_metadata}" install_dependencies
+}
+
+install_dependencies() {
+ grep -E "^dependencies:" ${METADATA} >/dev/null || return 0
+ (python - | while read dep; do fetch_dependency "$dep"; done) << EOF
+import sys,yaml
+for dep in yaml.load(open('${METADATA}', 'ro'))['dependencies']:
+ print '%s:%s' % (dep["name"], dep["source"])
+EOF
+}
+
+clean() {
+ log_info "Cleaning up ${BUILDDIR}"
+ [ -d ${BUILDDIR} ] && rm -rf ${BUILDDIR} || exit 0
+}
+
+salt_run() {
+ [ -e ${VEN_DIR}/bin/activate ] && source ${VENV_DIR}/bin/activate
+ salt-call ${SALT_OPTS} $*
+}
+
+prepare() {
+ [ -d ${BUILDDIR} ] && mkdir -p ${BUILDDIR}
+
+ which salt-call || setup_virtualenv
+ setup_pillar
+ setup_salt
+ install_dependencies
+}
+
+run() {
+ for pillar in ${PILLARDIR}/*.sls; do
+ state_name=$(basename ${pillar%.sls})
+ salt_run --id=${state_name} state.show_sls ${FORMULA_NAME} || (log_err "Execution of ${FORMULA_NAME}.${state_name} failed"; exit 1)
+ done
+}
+
+_atexit() {
+ RETVAL=$?
+ trap true INT TERM EXIT
+
+ if [ $RETVAL -ne 0 ]; then
+ log_err "Execution failed"
+ else
+ log_info "Execution successful"
+ fi
+ return $RETVAL
+}
+
+## Main
+trap _atexit INT TERM EXIT
+
+case $1 in
+ clean)
+ clean
+ ;;
+ prepare)
+ prepare
+ ;;
+ run)
+ run
+ ;;
+ *)
+ prepare
+ run
+ ;;
+esac