Merge "Added support for the schema output"
diff --git a/sphinx/_git.sls b/sphinx/_git.sls
index 2f5c6f4..c7d25a4 100644
--- a/sphinx/_git.sls
+++ b/sphinx/_git.sls
@@ -8,11 +8,11 @@
     - file: /srv/static/extern
     - pkg: git_packages
   - require_in:
-    - cmd: generate_sphinx_doc_{{ doc_name }}
+    - cmd: generate_sphinx_doc_git_{{ doc_name }}
 
-generate_sphinx_doc_{{ doc_name }}:
+generate_sphinx_doc_git_{{ doc_name }}:
   cmd.run:
-  - name: sphinx-build -b {{ doc.builder }} /srv/static/extern/{{ doc_name }}{% if doc.path is defined %}/{{ doc.path }}{% endif %} /srv/static/sites/{{ doc_name }}
+  - name: {{ sphinx_build_bin }} -b {{ doc.builder }} /srv/static/extern/{{ doc_name }}{% if doc.path is defined %}/{{ doc.path }}{% endif %} /srv/static/sites/{{ doc_name }}
   - require:
     - git: sphinx_source_{{ doc_name }}
     - file: /srv/static/sites/{{ doc_name }}
diff --git a/sphinx/_salt.sls b/sphinx/_salt.sls
index d69e411..5bc8645 100644
--- a/sphinx/_salt.sls
+++ b/sphinx/_salt.sls
@@ -77,6 +77,14 @@
   - defaults:
       doc_name: "{{ doc_name }}"
 
+/srv/static/extern/salt/source/services/schema.rst:
+  file.managed:
+  - source: salt://sphinx/files/salt/source/services/schema.rst
+  - template: jinja
+  - mode: 644
+  - require:
+    - file: salt_mine_doc_dirs
+
 /srv/static/extern/salt/source/nodes/index.rst:
   file.managed:
   - source: salt://sphinx/files/salt/source/nodes/index.rst
@@ -107,7 +115,7 @@
 
 {%- endif %}
 
-generate_sphinx_doc_{{ doc_name }}:
+generate_sphinx_doc_salt_{{ doc_name }}:
   cmd.run:
   - name: sphinx-build -b {{ doc.builder }} /srv/static/extern/salt/source /srv/static/sites/{{ doc_name }}
   - require:
diff --git a/sphinx/_schema.sls b/sphinx/_schema.sls
new file mode 100644
index 0000000..9af5df6
--- /dev/null
+++ b/sphinx/_schema.sls
@@ -0,0 +1,104 @@
+
+salt_schema_doc_dirs:
+  file.directory:
+  - names:
+    - /srv/static/extern/salt-schema/source/_static
+    - /srv/static/extern/salt-schema/source/services
+    - /srv/static/extern/salt-schema/source/nodes
+  - user: root
+  - mode: 755
+  - makedirs: true
+
+/srv/static/extern/salt-schema/Makefile:
+  file.managed:
+  - source: salt://sphinx/files/schema/Makefile
+  - mode: 644
+  - require:
+    - file: salt_schema_doc_dirs
+
+/srv/static/extern/salt-schema/source/conf.py:
+  file.managed:
+  - source: salt://sphinx/files/schema/source/conf.py
+  - template: jinja
+  - mode: 644
+  - require:
+    - file: salt_schema_doc_dirs
+  - defaults:
+      doc: {{ doc|yaml }}
+
+/srv/static/extern/salt-schema/source/index.rst:
+  file.managed:
+  - source: salt://sphinx/files/schema/source/index.rst
+  - template: jinja
+  - mode: 644
+  - require:
+    - file: salt_schema_doc_dirs
+  - defaults:
+      doc_name: "{{ doc_name }}"
+
+/srv/static/extern/salt-schema/source/services/catalog.rst:
+  file.managed:
+  - source: salt://sphinx/files/schema/source/services/catalog.rst
+  - template: jinja
+  - mode: 644
+  - require:
+    - file: salt_schema_doc_dirs
+  - defaults:
+      doc_name: "{{ doc_name }}"
+
+{### render service-schemas #}
+{%- set schema_list  = salt['modelschema.schema_list']() %}
+
+# Schema name should be filtered by uniq.
+# TBD with salt 2017+
+{%- for schema_name, schema_item in schema_list.items() %}
+{%- set schema  = salt['modelschema.schema_get'](schema_item.service, schema_item.role)[schema_item.service+'-'+schema_item.role] %}
+
+schema_dir_{{schema_item.service}}_{{schema_item.role}}:
+  file.directory:
+  - names:
+    - /srv/static/extern/salt-schema/source/services/{{ schema_item.service }}
+  - user: root
+  - mode: 755
+  - makedirs: true
+
+schema_rst_{{schema_item.service}}_{{schema_item.role}}:
+  file.managed:
+  - source: salt://sphinx/files/schema/source/services/schema.rst
+  - name: /srv/static/extern/salt-schema/source/services/{{schema_item.service}}/{{schema_item.role}}.rst
+  - template: jinja
+  - context:
+      schema_item: {{ schema_item }}
+      schema: {{ schema }}
+  - mode: 644
+  - require:
+    - file: schema_dir_{{schema_item.service}}_{{schema_item.role}}
+
+{%- endfor %}
+{### end render service-schemas #}
+
+{%- set mine_nodes = salt['mine.get']('*', 'grains.items') %}
+{%- if mine_nodes is mapping %}
+
+{%- for node_name, node_grains in mine_nodes.iteritems() %}
+
+/srv/static/extern/salt-schema/source/nodes/{{ node_name }}.rst:
+  file.managed:
+  - source: salt://sphinx/files/schema/source/nodes/node.rst
+  - template: jinja
+  - mode: 644
+  - require:
+    - file: salt_schema_doc_dirs
+  - defaults:
+      node_name: {{ node_name }}
+      node_grains: {{ node_grains|yaml }}
+
+{%- endfor %}
+
+{%- endif %}
+
+generate_sphinx_doc_schema_{{ doc_name }}:
+  cmd.run:
+  - name: {{ sphinx_build_bin }} -b {{ doc.builder }} /srv/static/extern/salt-schema/source /srv/static/sites/{{ doc_name }}
+  - require:
+    - file: /srv/static/sites/{{ doc_name }}
diff --git a/sphinx/files/salt/source/index.rst b/sphinx/files/salt/source/index.rst
index 1d6e69e..59a7ee1 100644
--- a/sphinx/files/salt/source/index.rst
+++ b/sphinx/files/salt/source/index.rst
@@ -7,7 +7,7 @@
 {%- if doc.description is defined %}
 {{ doc.description }}
 {%- else %}
-Model-driven documentation of SaltStack infrastructure deployment.
+Documentation generated from SaltStack infrastructure model.
 {%- endif %}
 
 .. toctree::
diff --git a/sphinx/files/schema/Makefile b/sphinx/files/schema/Makefile
new file mode 100644
index 0000000..3149b99
--- /dev/null
+++ b/sphinx/files/schema/Makefile
@@ -0,0 +1,181 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  texinfo    to make Texinfo files"
+	@echo "  info       to make Texinfo files and run them through makeinfo"
+	@echo "  gettext    to make PO message catalogs"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  xml        to make Docutils-native XML files"
+	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ifeq ($(origin BUILDDIR), undefined)
+	@echo "Warning! empty BUILDDIR variable!"
+else
+	[ ! -d $(BUILDDIR) ] || rm -rf $(BUILDDIR)/
+endif
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/reclass-doc.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/reclass-doc.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/reclass-doc"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/reclass-doc"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+latexpdfja:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through platex and dvipdfmx..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+	@echo "Run \`make' in that directory to run these through makeinfo" \
+	      "(use \`make info' here to do that automatically)."
+
+info:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo "Running Texinfo files through makeinfo..."
+	make -C $(BUILDDIR)/texinfo info
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+	@echo
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
+
+xml:
+	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+	@echo
+	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+pseudoxml:
+	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+	@echo
+	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/sphinx/files/schema/source/conf.py b/sphinx/files/schema/source/conf.py
new file mode 100644
index 0000000..a2370b5
--- /dev/null
+++ b/sphinx/files/schema/source/conf.py
@@ -0,0 +1,229 @@
+# -*- coding: utf-8 -*-
+#
+# Pillar Schema Specification build configuration file, created by
+# sphinx-quickstart on Thu Nov 26 15:14:56 2015.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+
+
+{%- if doc.theme is defined  %}
+{%- if doc.theme == "mosdocstheme"  %}
+import mosdocstheme
+execfile(mosdocstheme.get_common_conf_path() + '/common_conf.py')
+{%- else %}
+try:
+    from {{ doc.theme }}.theme_conf import *
+except:
+    pass
+{%- endif %}
+{%- endif %}
+
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'pillar-schema'
+copyright = u'{{ doc.year }}, {{ doc.author }}'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '{{ doc.version }}'
+# The full version, including alpha/beta/rc tags.
+release = '{{ doc.version }}'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'pillar-schema'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+    'papersize': 'a4paper',
+    'pointsize': '10pt',
+# 'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    ('index', 'pillar-schema.tex', u'{{ doc.get('title', 'Pillar Schema Specification') }}',
+     u'{{ doc.author }}', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
diff --git a/sphinx/files/schema/source/index.rst b/sphinx/files/schema/source/index.rst
new file mode 100644
index 0000000..b64786f
--- /dev/null
+++ b/sphinx/files/schema/source/index.rst
@@ -0,0 +1,8 @@
+
+.. toctree::
+   :maxdepth: 3
+
+   services/catalog
+
+..   nodes/index
+
diff --git a/sphinx/files/schema/source/nodes/index.rst b/sphinx/files/schema/source/nodes/index.rst
new file mode 100644
index 0000000..c483b30
--- /dev/null
+++ b/sphinx/files/schema/source/nodes/index.rst
@@ -0,0 +1,41 @@
+{%- set mine_nodes = salt['mine.get']('*', 'grains.items') %}
+{%- if mine_nodes is mapping %}
+
+====================
+Infrastructure Nodes
+====================
+
+Definition of all nodes within current infrastructure.
+
+.. list-table::
+   :widths: 30 15 55
+   :header-rows: 1
+
+   *  - **Node FQDN**
+      - **IP Addresses**
+      - **Assigned Services**
+{%- for node_name, node_grains in mine_nodes|dictsort %}
+   *  - :ref:`{{ node_name }}`
+{%- if node_grains.sphinx is defined %}
+      - {% for ip in node_grains.ipv4 %}
+        {%- if ip != "127.0.0.1" %}
+        * {{ ip }}
+        {%- endif %}
+        {%- endfor %}
+      - {% for service_name, service in node_grains.get('sphinx', {}).get('doc', {})|dictsort %}{% if service.role is mapping %}{% for role_name, role in service.role|dictsort %}{{ service_name }}-{{ role_name }} {% endfor %}{% endif %}{% endfor %}
+{%- else %}
+      - N/A
+      - N/A
+{%- endif %}
+{%- endfor %}
+
+.. toctree::
+   :maxdepth: 3
+
+{% for node_name, node_grains in mine_nodes|dictsort %}
+{%- if node_grains.get('sphinx_doc', {}) != None %}
+   {{ node_name }}
+{%- endif %}
+{% endfor %}
+
+{%- endif %}
diff --git a/sphinx/files/schema/source/nodes/node.rst b/sphinx/files/schema/source/nodes/node.rst
new file mode 100644
index 0000000..7f88971
--- /dev/null
+++ b/sphinx/files/schema/source/nodes/node.rst
@@ -0,0 +1,66 @@
+{% macro render_list(param) %}
+{%- if param %}
+   {%- if param is mapping %}
+      {%- for key, value in param.iteritems() %}
+- {{ key }}: {{ value }}
+      {%- endfor %}
+   {%- elif param is string or param is number %}
+{{ param }}
+   {%- else %}
+      {%- for p in param %}
+- {{ p }}
+      {%- endfor %}
+   {%- endif %}
+{%- else %}
+None
+{%- endif %}
+{% endmacro %}
+
+.. _{{ node_name }}:
+
+===============================================
+{{ node_name }}
+===============================================
+
+{%- if node_grains.get('sphinx_doc', {}) is not none %}
+
+   {%- for service_name, service in node_grains.get('sphinx', {}).get('doc', {})|dictsort %}
+
+Service {{ service_name }}
+===============================================
+
+.. list-table::
+   :widths: 15 15 70
+   :header-rows: 1
+
+   *  - **Service Role**
+      - **Parameter**
+      - **Value**
+   {%- if service.role is mapping %}
+      {%- for role_name, role in service.role|dictsort %}
+         {%- if role.get('param', {}) %}
+            {%- for param_name, param in role.get('param', {})|dictsort %}
+   *  - {{ service_name }}-{{ role_name }}
+               {%- if param is mapping %}
+      - {{ param.get('name', param_name) }}
+      -
+{{ render_list(param.value)|indent(8, True) }}
+               {%- else %}
+      - {{ param_name }}
+      - {{ param }}
+               {%- endif %}
+            {%- endfor %}
+         {%- endif %}
+      {%- endfor %}
+   {%- endif %}
+
+   {%- endfor %}
+
+{%- else %}
+
+This node has no documentation configured.
+
+{%- endif %}
+{#-
+   vim: syntax=jinja
+#}
diff --git a/sphinx/files/schema/source/services/catalog.rst b/sphinx/files/schema/source/services/catalog.rst
new file mode 100644
index 0000000..cb6eaa0
--- /dev/null
+++ b/sphinx/files/schema/source/services/catalog.rst
@@ -0,0 +1,37 @@
+
+==============================
+Overview of Available Services
+==============================
+
+Simple oveview of all defined services and their description.
+
+{%- set services = {} %}
+{%- for node_name, node_grains in salt['mine.get']('*', 'grains.items')|dictsort %}
+  {%- if node_grains.get('sphinx_doc', {}) != None %}
+  {%- set _dummy = services.update(node_grains.get('sphinx', {}).get('doc', {})) %}
+  {%- endif %}
+{%- endfor %}
+
+.. list-table::
+   :widths: 20 80
+   :header-rows: 1
+
+   *  - **Service**
+      - **Description**
+{%- for service_name, service in services|dictsort %}
+   *  - {{ service.name }}
+      - {{ service.get('description', 'nodescr') }}
+{%- endfor %}
+
+
+
+.. toctree::
+   :maxdepth: 10
+
+{% set schema_list  = salt['modelschema.schema_list']() -%}
+{%- for schema_name, schema_item in schema_list.iteritems() %}
+{%- set schema  = salt['modelschema.schema_get'](schema_item.service, schema_item.role)[schema_item.service+'-'+schema_item.role] %}
+   {{schema_item.service}}/{{schema_item.role}}.rst
+{%- endfor %}
+
+
diff --git a/sphinx/files/schema/source/services/schema.rst b/sphinx/files/schema/source/services/schema.rst
new file mode 100644
index 0000000..bc2cc43
--- /dev/null
+++ b/sphinx/files/schema/source/services/schema.rst
@@ -0,0 +1,114 @@
+
+==============================
+Metadata Schema Specifications
+==============================
+
+Service {{ schema_item.service }} {{ schema_item.role }}
+========================================================
+
+Core Properties
+---------------
+
+{# Macro, process only one schema object #}
+{%- macro chunk_object(o_name,obj) %}
+{% set vars = {'is_ref': False, 'descr' : obj.get('description', 'description_notset'), 'type' : obj.get('type', 'ERROR') } %}
+{%- if "properties" in obj %}
+  {%- if vars.update({'is_ref': obj.get("properties",{}).get('$ref', {}) }) %} {% endif %}
+{%- elif 'patternProperties' in obj and obj.patternProperties.get('$ref', False) %}
+  {%- if vars.update({'is_ref': obj.patternProperties.get('$ref', False)}) %} {% endif %}
+{%- elif 'patternProperties' in obj and not obj.patternProperties.get('$ref', {}) %}
+  {%- for key, value in obj.patternProperties.iteritems() %}
+    {%- if '$ref' in value %}
+      {%- if vars.update({'is_ref': value.get('$ref',False) })  %} {% endif %}
+    {%- endif %}
+  {% endfor %}
+{%- elif '$ref' in obj %}
+  {%- if vars.update({'is_ref': obj.get('$ref', False) }) %} {% endif %}
+{%- endif %}
+  {%- if vars.is_ref %}
+   *  - {{ o_name }}
+      - {{ vars.type }}
+      - {{ vars.descr }}
+        {{ 'For details, see: :ref:`' + vars.is_ref|replace('#/definitions/','') + '`'}}
+  {%- elif not vars.is_ref and "properties" in obj %}
+    {%- for prop_name, prop in obj.properties.items() %}
+       {{ chunk_object(prop_name, prop) }}
+    {%- endfor %}
+  {%- else %}
+   *  - {{ o_name }}
+      - {{ vars.type }}
+      - {{ vars.descr }}
+  {%- endif %}
+{%- endmacro %}
+
+{# Macro, process only one schema array #}
+{%- macro chunk_array(i_name,item) %}
+{%- set is_ref = False %}
+{%- set _descr = item.get('description', 'description_notset') %}
+{%- set _type = item.get('type', 'ERROR') %}
+{%- if '$ref' in item.get("items",[])%}
+  {%- set is_ref = item.get("items",[]).get('$ref', False) %}
+{%- endif %}
+   *  - {{ i_name }}
+      - {{ _type }}
+  {%- if is_ref %}
+      - {{ _descr }}
+        {{ 'For details, see: :ref:`' + is_ref|replace('#/definitions/','') + '`'}}
+  {%- else %}
+      - {{ '**NO REF** ' +_descr }}
+  {%- endif %}
+{%- endmacro %}
+{###############}
+
+.. list-table::
+   :header-rows: 1
+   :widths: 1 1 4
+
+   *  - **Name**
+      - **Type**
+      - **Description**
+{%- for param_name, param in schema.properties.items() %}
+{%- set _descr = param.get('description', 'description_notset') %}
+{%- set _type = param.get('type', 'ERROR') %}
+     {%- if _type == 'object' -%}
+       {{ chunk_object(param_name, param) }}
+     {%- elif _type == 'array' -%}
+       {{ chunk_array(param_name, param) }}
+     {%- else %}
+   *  - {{ param_name }}
+      - {{ _type }}
+      - {{ _descr }}
+     {%- endif %}
+{%- endfor %}
+
+
+{%- if schema.get('definitions', None) != None %} {#2#}
+
+{%- for def_name, param in schema.definitions.items() %} {#3#}
+
+{{ '.. _' + def_name|lower + ':' }}
+
+{{ def_name }} definition
+------------------------------------------
+
+.. list-table::
+   :header-rows: 1
+   :widths: 1 1 4
+
+   *  - **Name**
+      - **Type**
+      - **Description**
+{%- set _descr = param.get('description', 'description_notset') %}
+{%- set _type = param.get('type', 'ERROR') %}
+     {%- if _type == 'object' -%}
+       {{ chunk_object(def_name, param) }}
+     {%- elif _type == 'array' -%}
+       {{ chunk_array(def_name, param) }}
+     {%- else %}
+   *  - {{ def_name }}
+      - {{ _type }}
+      - {{ _descr }}
+     {%- endif %}
+{% endfor %} {#3#}
+
+{% endif %} {#2#}
diff --git a/sphinx/server.sls b/sphinx/server.sls
index 8d01129..f29eb80 100755
--- a/sphinx/server.sls
+++ b/sphinx/server.sls
@@ -28,24 +28,31 @@
   - require:
     - file: /srv/static/sites
 
+{%- if doc.get("prebuilded_venv", False) %}
+  {%- set sphinx_build_bin = doc.prebuilded_venv + "/sphinx-build"  %}
+{% else %}
+  {%- set sphinx_build_bin = "sphinx-build"  %}
+{%- endif %}
+
+{% with sphinx_build_bin=sphinx_build_bin %}
 {%- if doc.source.engine in ['reclass', 'salt-mine'] %}
 {%- include "sphinx/_salt.sls" %}
 {%- endif -%}
 
+{%- if doc.source.engine in ['pillar-schema'] %}
+{%- include "sphinx/_schema.sls" %}
+{%- endif -%}
+
 {%- if doc.source.engine == 'git' %}
 {%- include "sphinx/_git.sls" %}
 {%- endif -%}
-
-{%- if doc.source.engine == 'local' %}
+{% endwith %}
 
 generate_sphinx_doc_{{ doc_name }}:
   cmd.run:
-  - name: sphinx-build -b {{ doc.builder }} {{ doc.source.path }} /srv/static/sites/{{ doc_name }}
+  - name: {{ sphinx_build_bin }} -b {{ doc.builder }} /srv/static/extern/salt-schema/source /srv/static/sites/{{ doc_name }}
   - require:
     - file: /srv/static/sites/{{ doc_name }}
-
-{%- endif %}
-
 {%- endfor %}
 
-{%- endif %}
\ No newline at end of file
+{%- endif %}