Merge tag '2016.12.1' into debian/unstable

2016.12.1
diff --git a/FORMULA b/FORMULA
new file mode 100644
index 0000000..01f3902
--- /dev/null
+++ b/FORMULA
@@ -0,0 +1,8 @@
+name: keystone
+os: Debian, RedHat
+os_family: Debian, RedHat
+version: 201606
+release: 1
+summary: Formula for installing and configuring keystone
+description: Formula for installing and configuring keystone
+top_level_dir: keystone
diff --git a/README.rst b/README.rst
index 0d038d3..ff64b7b 100644
--- a/README.rst
+++ b/README.rst
@@ -2,7 +2,10 @@
 OpenStack Keystone
 ==================
 
-Keystone provides authentication, authorization and service discovery mechanisms via HTTP primarily for use by projects in the OpenStack family. It is most commonly deployed as an HTTP interface to existing identity systems, such as LDAP.
+Keystone provides authentication, authorization and service discovery
+mechanisms via HTTP primarily for use by projects in the OpenStack family. It
+is most commonly deployed as an HTTP interface to existing identity systems,
+such as LDAP.
 
 From Kilo release Keystone v3 endpoint has definition without version in url
 
@@ -18,9 +21,11 @@
 Sample pillars
 ==============
 
-.. caution:: 
+.. caution::
 
-    When you use localhost as your database host (keystone:server:database:host), sqlalchemy will try to connect to /var/run/mysql/mysqld.sock, may cause issues if you located your mysql socket elsewhere
+    When you use localhost as your database host (keystone:server:
+    atabase:host), sqlalchemy will try to connect to /var/run/mysql/
+    mysqld.sock, may cause issues if you located your mysql socket elsewhere
 
 Full stacked keystone
 
@@ -162,6 +167,7 @@
         ...
         tokens:
           engine: fernet
+          max_active_keys: 3
         ...
 
 Keystone domain with LDAP backend, using SQL for role/project assignment
@@ -255,13 +261,143 @@
           virtual_host: '/openstack'
           ha_queues: true
 
-Read more
-=========
+Enable CADF audit notification
 
-* http://docs.openstack.org/developer/keystone/configuration.html
-* http://docs.openstack.org/developer/keystone/architecture.html
-* http://docs.saltstack.com/ref/states/all/salt.states.keystone.html
-* http://docs.saltstack.com/ref/modules/all/salt.modules.keystone.html
-* http://www.sebastien-han.fr/blog/2012/12/12/cleanup-keystone-tokens/
-* http://www-01.ibm.com/support/knowledgecenter/SS4KMC_2.2.0/com.ibm.sco.doc_2.2/t_memcached_keystone.html?lang=en
-* https://bugs.launchpad.net/tripleo/+bug/1203910
+.. code-block:: yaml
+
+    keystone:
+      server:
+        notification: true
+        notification_format: cadf
+
+Run keystone under Apache
+
+.. code-block:: yaml
+
+    keystone:
+      server:
+        service_name: apache2
+    apache:
+      server:
+        enabled: true
+        default_mpm: event
+        site:
+          keystone:
+            enabled: true
+            type: keystone
+            name: wsgi
+            host:
+              name: ${linux:network:fqdn}
+        modules:
+          - wsgi
+
+Enable Federated keystone
+
+.. code-block:: yaml
+
+    keystone:
+      server:
+        websso:
+          protocol: saml2
+          remote_id_attribute: Shib-Identity-Provider
+          federation_driver: keystone.contrib.federation.backends.sql.Federation
+          trusted_dashboard:
+            - http://${_param:proxy_vip_address_public}/horizon/auth/websso/
+    apache:
+      server:
+        pkgs:
+          - apache2
+          - libapache2-mod-shib2
+        modules:
+          - wsgi
+          - shib2
+
+Keystone client
+---------------
+
+Service endpoints enforcement with service token
+
+.. code-block:: yaml
+
+    keystone:
+      client:
+        enabled: true
+        server:
+          keystone01:
+            admin:
+              host: 10.0.0.2
+              port: 35357
+              token: 'service_token'
+            service:
+              nova:
+                type: compute
+                description: OpenStack Compute Service
+                endpoints:
+                - region: region01
+                  public_address: 172.16.10.1
+                  public_port: 8773
+                  public_path: '/v2'
+                  internal_address: 172.16.10.1
+                  internal_port: 8773
+                  internal_path: '/v2'
+                  admin_address: 172.16.10.1
+                  admin_port: 8773
+                  admin_path: '/v2'
+
+Project, users, roles enforcement with admin user
+
+.. code-block:: yaml
+
+    keystone:
+      client:
+        enabled: true
+        server:
+          keystone01:
+            admin:
+              host: 10.0.0.2
+              port: 5000
+              project: 'token'
+              user: admin
+              password: 'passwd'
+            roles:
+            - admin
+            - member
+            project:
+              tenant01:
+                description: "test env"
+                user:
+                  user01:
+                    email: jdoe@domain.com
+                    is_admin: true
+                    password: some
+                  user02:
+                    email: jdoe2@domain.com
+                    password: some
+                    roles:
+                    - custom-roles
+
+Documentation and Bugs
+======================
+
+To learn how to deploy OpenStack Salt, consult the documentation available
+online at:
+
+    https://wiki.openstack.org/wiki/OpenStackSalt
+
+In the unfortunate event that bugs are discovered, they should be reported to
+the appropriate bug tracker. If you obtained the software from a 3rd party
+operating system vendor, it is often wise to use their own bug tracker for
+reporting problems. In all other cases use the master OpenStack bug tracker,
+available at:
+
+    http://bugs.launchpad.net/openstack-salt
+
+Developers wishing to work on the OpenStack Salt project should always base
+their work on the latest formulas code, available from the master GIT
+repository at:
+
+    https://git.openstack.org/cgit/openstack/salt-formula-keystone
+
+Developers should also join the discussion on the IRC list, at:
+
+    https://wiki.openstack.org/wiki/Meetings/openstack-salt
diff --git a/other-requirements.txt b/bindep.txt
similarity index 100%
rename from other-requirements.txt
rename to bindep.txt
diff --git a/keystone/client.sls b/keystone/client.sls
deleted file mode 100644
index 2f6edbd..0000000
--- a/keystone/client.sls
+++ /dev/null
@@ -1,48 +0,0 @@
-{%- from "keystone/map.jinja" import client with context %}
-{%- if client.enabled %}
-
-keystone_client_packages:
-  pkg.installed:
-  - names: {{ client.pkgs }}
-
-{%- if client.tenant is defined %}
-
-keystone_client_roles:
-  keystone.role_present:
-  - names: {{ client.roles }}
-
-{%- for tenant_name, tenant in client.get('tenant', {}).iteritems() %}
-
-keystone_tenant_{{ tenant_name }}:
-  keystone.tenant_present:
-  - name: {{ tenant_name }}
-  - require:
-    - keystone: keystone_client_roles
-
-{%- for user_name, user in tenant.get('user', {}).iteritems() %}
-
-keystone_{{ tenant_name }}_user_{{ user_name }}:
-  keystone.user_present:
-  - name: {{ user_name }}
-  - password: {{ user.password }}
-  - email: {{ user.get('email', 'root@localhost') }}
-  - tenant: {{ tenant_name }}
-  - roles:
-      "{{ tenant_name }}":
-        {%- if user.get('is_admin', False) %}
-        - admin
-        {%- elif user.get('roles', False) %}
-        {{ user.roles }}
-        {%- else %}
-        - Member
-        {%- endif %}
-  - require:
-    - keystone: keystone_tenant_{{ tenant_name }}
-
-{%- endfor %}
-
-{%- endfor %}
-
-{%- endif %}
-
-{%- endif %}
diff --git a/keystone/client/init.sls b/keystone/client/init.sls
new file mode 100644
index 0000000..4a3f11d
--- /dev/null
+++ b/keystone/client/init.sls
@@ -0,0 +1,5 @@
+
+include:
+- keystone.client.service
+- keystone.client.project
+- keystone.client.server
diff --git a/keystone/client/project.sls b/keystone/client/project.sls
new file mode 100644
index 0000000..bb0d30e
--- /dev/null
+++ b/keystone/client/project.sls
@@ -0,0 +1,65 @@
+{%- from "keystone/map.jinja" import client with context %}
+{%- if client.enabled %}
+
+{%- if client.tenant is defined %}
+
+keystone_salt_config:
+  file.managed:
+    - name: /etc/salt/minion.d/keystone.conf
+    - template: jinja
+    - source: salt://keystone/files/salt-minion.conf
+    - mode: 600
+
+keystone_client_roles:
+  keystone.role_present:
+  - names: {{ client.roles }}
+  - connection_user: {{ client.server.user }}
+  - connection_password: {{ client.server.password }}
+  - connection_tenant: {{ client.server.tenant }}
+  - connection_auth_url: 'http://{{ client.server.host }}:{{ client.server.public_port }}/v2.0/'
+  - require:
+    - file: keystone_salt_config
+
+{%- for tenant_name, tenant in client.get('tenant', {}).iteritems() %}
+
+keystone_tenant_{{ tenant_name }}:
+  keystone.tenant_present:
+  - name: {{ tenant_name }}
+  - connection_user: {{ client.server.user }}
+  - connection_password: {{ client.server.password }}
+  - connection_tenant: {{ client.server.tenant }}
+  - connection_auth_url: 'http://{{ client.server.host }}:{{ client.server.public_port }}/v2.0/'
+  - require:
+    - keystone: keystone_client_roles
+
+{%- for user_name, user in tenant.get('user', {}).iteritems() %}
+
+keystone_{{ tenant_name }}_user_{{ user_name }}:
+  keystone.user_present:
+  - name: {{ user_name }}
+  - password: {{ user.password }}
+  - email: {{ user.get('email', 'root@localhost') }}
+  - tenant: {{ tenant_name }}
+  - roles:
+      "{{ tenant_name }}":
+        {%- if user.get('is_admin', False) %}
+        - admin
+        {%- elif user.get('roles', False) %}
+        {{ user.roles }}
+        {%- else %}
+        - Member
+        {%- endif %}
+  - connection_user: {{ client.server.user }}
+  - connection_password: {{ client.server.password }}
+  - connection_tenant: {{ client.server.tenant }}
+  - connection_auth_url: 'http://{{ client.server.host }}:{{ client.server.public_port }}/v2.0/'
+  - require:
+    - keystone: keystone_tenant_{{ tenant_name }}
+
+{%- endfor %}
+
+{%- endfor %}
+
+{%- endif %}
+
+{%- endif %}
diff --git a/keystone/client/server.sls b/keystone/client/server.sls
new file mode 100644
index 0000000..38d8169
--- /dev/null
+++ b/keystone/client/server.sls
@@ -0,0 +1,144 @@
+{%- from "keystone/map.jinja" import client with context %}
+{%- if client.enabled %}
+
+{%- for server_name, server in client.get('server', {}).iteritems() %}
+
+{%- if server.admin.get('api_version', '2') == '3' %}
+{%- set version = "v3" %}
+{%- else %}
+{%- set version = "v2.0" %}
+{%- endif %}
+
+{%- if server.admin.get('protocol', 'http') == 'http' %}
+{%- set protocol = 'http' %}
+{%- else %}
+{%- set protocol = 'https' %}
+{%- endif %}
+
+
+{%- if server.admin.token is defined %}
+{%- set connection_args = {'endpoint': protocol+'://'+server.admin.host+':'+server.admin.port|string+'/'+version,
+                           'token': server.admin.token} %}
+{%- else %}
+{%- set connection_args = {'auth_url': protocol+'://'+server.admin.host+':'+server.admin.port|string+'/'+version,
+                           'tenant': server.admin.project,
+                           'user': server.admin.user,
+                           'password': server.admin.password} %}
+{%- endif %}
+
+{%- if server.roles is defined %}
+
+keystone_{{ server_name }}_roles:
+  keystone.role_present:
+  - names: {{ server.roles }}
+  {%- if server.admin.token is defined %}
+  - connection_token: {{ connection_args.token }}
+  - connection_endpoint: {{ connection_args.endpoint }}
+  {%- else %}
+  - connection_user: {{ connection_args.user }}
+  - connection_password: {{ connection_args.password }}
+  - connection_tenant: {{ connection_args.tenant }}
+  - connection_auth_url: {{ connection_args.auth_url }}
+  {%- endif %}
+
+{%- endif %}
+
+{% for service_name, service in server.get('service', {}).iteritems() %}
+
+keystone_{{ server_name }}_service_{{ service_name }}:
+  keystone.service_present:
+  - name: {{ service_name }}
+  - service_type: {{ service.type }}
+  - description: {{ service.description }}
+  {%- if server.admin.token is defined %}
+  - connection_token: {{ connection_args.token }}
+  - connection_endpoint: {{ connection_args.endpoint }}
+  {%- else %}
+  - connection_user: {{ connection_args.user }}
+  - connection_password: {{ connection_args.password }}
+  - connection_tenant: {{ connection_args.tenant }}
+  - connection_auth_url: {{ connection_args.auth_url }}
+  {%- endif %}
+
+{%- for endpoint in service.get('endpoints', ()) %}
+
+keystone_{{ server_name }}_service_{{ service_name }}_endpoint_{{ endpoint.region }}:
+  keystone.endpoint_present:
+  - name: {{ service_name }}
+  - publicurl: '{{ endpoint.get('public_protocol', 'http') }}://{{ endpoint.public_address }}:{{ endpoint.public_port }}{{ endpoint.public_path }}'
+  - internalurl: '{{ endpoint.get('internal_protocol', 'http') }}://{{ endpoint.internal_address }}:{{ endpoint.internal_port }}{{ endpoint.internal_path }}'
+  - adminurl: '{{ endpoint.get('admin_protocol', 'http') }}://{{ endpoint.admin_address }}:{{ endpoint.admin_port }}{{ endpoint.admin_path }}'
+  - region: {{ endpoint.region }}
+  - require:
+    - keystone: keystone_{{ server_name }}_service_{{ service_name }}
+  {%- if server.admin.token is defined %}
+  - connection_token: {{ connection_args.token }}
+  - connection_endpoint: {{ connection_args.endpoint }}
+  {%- else %}
+  - connection_user: {{ connection_args.user }}
+  - connection_password: {{ connection_args.password }}
+  - connection_tenant: {{ connection_args.tenant }}
+  - connection_auth_url: {{ connection_args.auth_url }}
+  {%- endif %}
+
+{%- endfor %}
+
+{%- endfor %}
+
+{%- for tenant_name, tenant in server.get('project', {}).iteritems() %}
+
+keystone_{{ server_name }}_tenant_{{ tenant_name }}:
+  keystone.tenant_present:
+  - name: {{ tenant_name }}
+  {%- if tenant.description is defined %}
+  - description: {{ tenant.description }}
+  {%- endif %}
+  {%- if server.admin.token is defined %}
+  - connection_token: {{ connection_args.token }}
+  - connection_endpoint: {{ connection_args.endpoint }}
+  {%- else %}
+  - connection_user: {{ connection_args.user }}
+  - connection_password: {{ connection_args.password }}
+  - connection_tenant: {{ connection_args.tenant }}
+  - connection_auth_url: {{ connection_args.auth_url }}
+  {%- endif %}
+
+{%- for user_name, user in tenant.get('user', {}).iteritems() %}
+
+keystone_{{ server_name }}_tenant_{{ tenant_name }}_user_{{ user_name }}:
+  keystone.user_present:
+  - name: {{ user_name }}
+  - password: {{ user.password }}
+  {%- if user.email is defined %}
+  - email: {{ user.email }}
+  {%- endif %}
+  - tenant: {{ tenant_name }}
+  - roles:
+      "{{ tenant_name }}":
+        {%- if user.get('is_admin', False) %}
+        - admin
+        {%- elif user.get('roles', False) %}
+        {{ user.roles }}
+        {%- else %}
+        - Member
+        {%- endif %}
+  - require:
+    - keystone: keystone_{{ server_name }}_tenant_{{ tenant_name }}
+    - keystone: keystone_{{ server_name }}_roles
+  {%- if server.admin.token is defined %}
+  - connection_token: {{ connection_args.token }}
+  - connection_endpoint: {{ connection_args.endpoint }}
+  {%- else %}
+  - connection_user: {{ connection_args.user }}
+  - connection_password: {{ connection_args.password }}
+  - connection_tenant: {{ connection_args.tenant }}
+  - connection_auth_url: {{ connection_args.auth_url }}
+  {%- endif %}
+
+{%- endfor %}
+
+{%- endfor %}
+
+{%- endfor %}
+
+{%- endif %}
diff --git a/keystone/client/service.sls b/keystone/client/service.sls
new file mode 100644
index 0000000..40c68df
--- /dev/null
+++ b/keystone/client/service.sls
@@ -0,0 +1,8 @@
+{%- from "keystone/map.jinja" import client with context %}
+{%- if client.enabled %}
+
+keystone_client_packages:
+  pkg.installed:
+  - names: {{ client.pkgs }}
+
+{%- endif %}
diff --git a/keystone/files/apache.conf b/keystone/files/apache.conf
new file mode 100644
index 0000000..b47d1ee
--- /dev/null
+++ b/keystone/files/apache.conf
@@ -0,0 +1,2 @@
+{%- from "keystone/map.jinja" import server with context %}
+{%- include "keystone/files/"+server.version+"/wsgi-keystone.conf" %}
diff --git a/keystone/files/collectd_check_openstack_api.conf b/keystone/files/collectd_check_openstack_api.conf
new file mode 100644
index 0000000..9dfdcdd
--- /dev/null
+++ b/keystone/files/collectd_check_openstack_api.conf
@@ -0,0 +1,10 @@
+Import "check_openstack_api"
+
+<Module "check_openstack_api">
+    KeystoneUrl "{{ plugin.url }}"
+    Username "{{ plugin.username }}"
+    Password "{{ plugin.password }}"
+    Tenant "{{ plugin.tenant }}"
+    MaxRetries "2"
+    Timeout "20"
+</Module>
diff --git a/keystone/files/collectd_openstack_keystone.conf b/keystone/files/collectd_openstack_keystone.conf
new file mode 100644
index 0000000..61ea023
--- /dev/null
+++ b/keystone/files/collectd_openstack_keystone.conf
@@ -0,0 +1,10 @@
+Import "openstack_keystone"
+
+<Module "openstack_keystone">
+    KeystoneUrl "{{ plugin.url }}"
+    Username "{{ plugin.username }}"
+    Password "{{ plugin.password }}"
+    Tenant "{{ plugin.tenant }}"
+    MaxRetries "2"
+    Timeout "20"
+</Module>
diff --git a/keystone/files/entrypoint.sh b/keystone/files/entrypoint.sh
new file mode 100644
index 0000000..b139f2e
--- /dev/null
+++ b/keystone/files/entrypoint.sh
@@ -0,0 +1,14 @@
+{%- from "keystone/map.jinja" import server with context -%}
+#!/bin/bash -e
+
+cat /srv/salt/pillar/keystone-server.sls | envsubst > /tmp/keystone-server.sls
+mv /tmp/keystone-server.sls /srv/salt/pillar/keystone-server.sls
+
+salt-call --local --retcode-passthrough state.highstate
+service {{ server.service_name }} stop || true
+
+su keystone --shell=/bin/sh -c '/usr/bin/keystone-all --config-file=/etc/keystone/keystone.conf'
+
+{#-
+vim: syntax=jinja
+-#}
diff --git a/keystone/files/grafana_dashboards/keystone_influxdb.json b/keystone/files/grafana_dashboards/keystone_influxdb.json
new file mode 100644
index 0000000..36cc2b8
--- /dev/null
+++ b/keystone/files/grafana_dashboards/keystone_influxdb.json
@@ -0,0 +1,2019 @@
+{
+  "annotations": {
+    "enable": true,
+    "list": [
+      {
+        "datasource": "lma",
+        "enable": true,
+        "iconColor": "#C0C6BE",
+        "iconSize": 13,
+        "lineColor": "rgba(255, 96, 96, 0.592157)",
+        "name": "Status",
+        "query": "select title,tags,text from annotations where $timeFilter and cluster = 'keystone'",
+        "showLine": true,
+        "tagsColumn": "tags",
+        "textColumn": "text",
+        "titleColumn": "title"
+      }
+    ]
+  },
+  "editable": true,
+  "hideControls": false,
+  "id": null,
+  "links": [],
+  "originalTitle": "Keystone",
+  "refresh": "1m",
+  "rows": [
+    {
+      "collapse": false,
+      "editable": true,
+      "height": "250px",
+      "panels": [
+        {
+          "cacheTimeout": null,
+          "colorBackground": true,
+          "colorValue": false,
+          "colors": [
+            "rgba(71, 212, 59, 0.4)",
+            "rgba(241, 181, 37, 0.73)",
+            "rgba(225, 40, 40, 0.59)"
+          ],
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "format": "none",
+          "gauge": {
+            "maxValue": 100,
+            "minValue": 0,
+            "show": false,
+            "thresholdLabels": false,
+            "thresholdMarkers": true
+          },
+          "id": 6,
+          "interval": "> 60s",
+          "links": [],
+          "maxDataPoints": 100,
+          "nullPointMode": "connected",
+          "nullText": null,
+          "postfix": "",
+          "postfixFontSize": "50%",
+          "prefix": "",
+          "prefixFontSize": "50%",
+          "span": 2,
+          "sparkline": {
+            "fillColor": "rgba(31, 118, 189, 0.18)",
+            "full": false,
+            "lineColor": "rgb(31, 120, 193)",
+            "show": false
+          },
+          "targets": [
+            {
+              "column": "value",
+              "condition": "",
+              "dsType": "influxdb",
+              "fill": "",
+              "function": "last",
+              "groupBy": [
+                {
+                  "params": [
+                    "$interval"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "null"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "groupByTags": [],
+              "groupby_field": "",
+              "interval": "",
+              "measurement": "cluster_status",
+              "policy": "default",
+              "query": "SELECT last(\"value\") FROM \"cluster_status\" WHERE \"environment_label\" =~ /^$environment$/ AND \"cluster_name\" = 'keystone' AND $timeFilter GROUP BY time($interval) fill(null)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "value"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "last"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "environment_label",
+                  "operator": "=",
+                  "value": "$environment"
+                },
+                {
+                  "key": "cluster_name",
+                  "operator": "=",
+                  "value": "keystone"
+                }
+              ]
+            }
+          ],
+          "thresholds": "1,2",
+          "title": "",
+          "type": "singlestat",
+          "valueFontSize": "80%",
+          "valueMaps": [
+            {
+              "op": "=",
+              "text": "no data",
+              "value": "null"
+            },
+            {
+              "op": "=",
+              "text": "OKAY",
+              "value": "0"
+            },
+            {
+              "op": "=",
+              "text": "WARN",
+              "value": "1"
+            },
+            {
+              "op": "=",
+              "text": "FAIL",
+              "value": "2"
+            },
+            {
+              "op": "=",
+              "text": "UNKNOWN",
+              "value": "3"
+            }
+          ],
+          "valueName": "current"
+        },
+        {
+          "cacheTimeout": null,
+          "colorBackground": false,
+          "colorValue": false,
+          "colors": [
+            "rgba(71, 212, 59, 0.4)",
+            "rgba(245, 150, 40, 0.73)",
+            "rgba(225, 40, 40, 0.59)"
+          ],
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "format": "none",
+          "gauge": {
+            "maxValue": 100,
+            "minValue": 0,
+            "show": false,
+            "thresholdLabels": false,
+            "thresholdMarkers": true
+          },
+          "id": 13,
+          "interval": "> 60s",
+          "links": [],
+          "maxDataPoints": 100,
+          "nullPointMode": "connected",
+          "nullText": null,
+          "postfix": "",
+          "postfixFontSize": "50%",
+          "prefix": "",
+          "prefixFontSize": "50%",
+          "span": 2,
+          "sparkline": {
+            "fillColor": "rgba(31, 118, 189, 0.18)",
+            "full": false,
+            "lineColor": "rgb(31, 120, 193)",
+            "show": true
+          },
+          "targets": [
+            {
+              "column": "value",
+              "condition": "",
+              "dsType": "influxdb",
+              "fill": "",
+              "function": "count",
+              "groupBy": [
+                {
+                  "interval": "auto",
+                  "params": [
+                    "auto"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "0"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "groupby_field": "",
+              "interval": "",
+              "measurement": "openstack_keystone_http_response_times",
+              "policy": "default",
+              "query": "SELECT sum(\"count\") FROM \"openstack_keystone_http_response_times\" WHERE \"hostname\" =~ /$server/ AND \"http_status\" = '5xx' AND $timeFilter GROUP BY time($interval) fill(0)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "count"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "sum"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "hostname",
+                  "operator": "=~",
+                  "value": "/$server/"
+                },
+                {
+                  "condition": "AND",
+                  "key": "http_status",
+                  "operator": "=",
+                  "value": "5xx"
+                }
+              ]
+            }
+          ],
+          "thresholds": "0,1",
+          "title": "HTTP 5xx errors",
+          "type": "singlestat",
+          "valueFontSize": "80%",
+          "valueMaps": [
+            {
+              "op": "=",
+              "text": "0",
+              "value": "null"
+            }
+          ],
+          "valueName": "current"
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "fill": 0,
+          "grid": {
+            "threshold1": null,
+            "threshold1Color": "rgba(216, 200, 27, 0.27)",
+            "threshold2": null,
+            "threshold2Color": "rgba(234, 112, 112, 0.22)"
+          },
+          "id": 7,
+          "interval": ">60s",
+          "legend": {
+            "alignAsTable": true,
+            "avg": true,
+            "current": false,
+            "max": true,
+            "min": true,
+            "show": true,
+            "sortDesc": true,
+            "total": false,
+            "values": true
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "connected",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "span": 8,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "alias": "GET",
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "mean",
+              "groupBy": [
+                {
+                  "interval": "auto",
+                  "params": [
+                    "auto"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "0"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "hide": false,
+              "interval": "",
+              "measurement": "openstack_keystone_http_response_times",
+              "policy": "default",
+              "query": "SELECT max(\"upper_90\") FROM \"openstack_keystone_http_response_times\" WHERE \"hostname\" =~ /$server/ AND \"http_method\" = 'GET' AND $timeFilter GROUP BY time($interval) fill(0)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "upper_90"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "max"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "hostname",
+                  "operator": "=~",
+                  "value": "/$server/"
+                },
+                {
+                  "condition": "AND",
+                  "key": "http_method",
+                  "operator": "=",
+                  "value": "GET"
+                }
+              ]
+            },
+            {
+              "alias": "POST",
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "mean",
+              "groupBy": [
+                {
+                  "interval": "auto",
+                  "params": [
+                    "auto"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "0"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "hide": false,
+              "interval": "",
+              "measurement": "openstack_keystone_http_response_times",
+              "policy": "default",
+              "query": "SELECT max(\"upper_90\") FROM \"openstack_keystone_http_response_times\" WHERE \"hostname\" =~ /$server/ AND \"http_method\" = 'POST' AND $timeFilter GROUP BY time($interval) fill(0)",
+              "rawQuery": false,
+              "refId": "B",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "upper_90"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "max"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "hostname",
+                  "operator": "=~",
+                  "value": "/$server/"
+                },
+                {
+                  "condition": "AND",
+                  "key": "http_method",
+                  "operator": "=",
+                  "value": "POST"
+                }
+              ]
+            },
+            {
+              "alias": "PUT",
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "mean",
+              "groupBy": [
+                {
+                  "interval": "auto",
+                  "params": [
+                    "auto"
+                  ],
+                  "type": "time"
+                }
+              ],
+              "hide": false,
+              "interval": "",
+              "measurement": "openstack_keystone_http_response_times",
+              "policy": "default",
+              "query": "SELECT max(\"upper_90\") FROM \"openstack_keystone_http_response_times\" WHERE \"hostname\" =~ /$server/ AND \"http_method\" = 'PUT' AND $timeFilter GROUP BY time($interval)",
+              "rawQuery": false,
+              "refId": "C",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "upper_90"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "max"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "hostname",
+                  "operator": "=~",
+                  "value": "/$server/"
+                },
+                {
+                  "condition": "AND",
+                  "key": "http_method",
+                  "operator": "=",
+                  "value": "PUT"
+                }
+              ]
+            },
+            {
+              "alias": "DELETE",
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "mean",
+              "groupBy": [
+                {
+                  "interval": "auto",
+                  "params": [
+                    "auto"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "0"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "hide": false,
+              "interval": "",
+              "measurement": "openstack_keystone_http_response_times",
+              "policy": "default",
+              "query": "SELECT max(\"upper_90\") FROM \"openstack_keystone_http_response_times\" WHERE \"hostname\" =~ /$server/ AND \"http_method\" = 'DELETE' AND $timeFilter GROUP BY time($interval) fill(0)",
+              "rawQuery": false,
+              "refId": "D",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "upper_90"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "max"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "hostname",
+                  "operator": "=~",
+                  "value": "/$server/"
+                },
+                {
+                  "condition": "AND",
+                  "key": "http_method",
+                  "operator": "=",
+                  "value": "DELETE"
+                }
+              ]
+            }
+          ],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "HTTP response time on $server",
+          "tooltip": {
+            "msResolution": false,
+            "shared": true,
+            "value_type": "cumulative"
+          },
+          "type": "graph",
+          "xaxis": {
+            "show": true
+          },
+          "yaxes": [
+            {
+              "format": "s",
+              "logBase": 1,
+              "max": null,
+              "min": 0,
+              "show": true
+            },
+            {
+              "format": "short",
+              "logBase": 1,
+              "max": null,
+              "min": 0,
+              "show": true
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "fill": 1,
+          "grid": {
+            "threshold1": null,
+            "threshold1Color": "rgba(216, 200, 27, 0.27)",
+            "threshold2": null,
+            "threshold2Color": "rgba(234, 112, 112, 0.22)",
+            "thresholdLine": false
+          },
+          "id": 9,
+          "interval": "> 60s",
+          "legend": {
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": false,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 2,
+          "links": [],
+          "nullPointMode": "connected",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "span": 4,
+          "stack": false,
+          "steppedLine": true,
+          "targets": [
+            {
+              "alias": "healthy",
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "last",
+              "groupBy": [
+                {
+                  "params": [
+                    "$interval"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "0"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "groupByTags": [],
+              "measurement": "openstack_check_api",
+              "policy": "default",
+              "query": "SELECT last(\"value\") FROM \"openstack_check_api\" WHERE \"environment_label\" =~ /^$environment$/ AND \"service\" = 'keystone-public-api' AND $timeFilter GROUP BY time($interval) fill(0)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "value"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "last"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "environment_label",
+                  "operator": "=",
+                  "value": "$environment"
+                },
+                {
+                  "key": "service",
+                  "operator": "=",
+                  "value": "keystone-public-api"
+                }
+              ]
+            }
+          ],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "API Availability",
+          "tooltip": {
+            "msResolution": false,
+            "shared": false,
+            "value_type": "cumulative"
+          },
+          "type": "graph",
+          "xaxis": {
+            "show": true
+          },
+          "yaxes": [
+            {
+              "format": "none",
+              "label": "",
+              "logBase": 1,
+              "max": 1,
+              "min": 0,
+              "show": false
+            },
+            {
+              "format": "short",
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": false
+            }
+          ]
+        },
+        {
+          "aliasColors": {},
+          "bars": true,
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "fill": 0,
+          "grid": {
+            "threshold1": null,
+            "threshold1Color": "rgba(216, 200, 27, 0.27)",
+            "threshold2": null,
+            "threshold2Color": "rgba(234, 112, 112, 0.22)",
+            "thresholdLine": false
+          },
+          "id": 8,
+          "interval": "> 60s",
+          "legend": {
+            "alignAsTable": true,
+            "avg": false,
+            "current": false,
+            "hideEmpty": false,
+            "max": true,
+            "min": true,
+            "rightSide": false,
+            "show": true,
+            "total": true,
+            "values": true
+          },
+          "lines": false,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "connected",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "span": 8,
+          "stack": true,
+          "steppedLine": false,
+          "targets": [
+            {
+              "alias": "2xx",
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "count",
+              "groupBy": [
+                {
+                  "interval": "auto",
+                  "params": [
+                    "auto"
+                  ],
+                  "type": "time"
+                }
+              ],
+              "interval": "",
+              "measurement": "openstack_keystone_http_response_times",
+              "policy": "default",
+              "query": "SELECT sum(\"count\") FROM \"openstack_keystone_http_response_times\" WHERE \"hostname\" =~ /$server/ AND \"http_status\" = '2xx' AND $timeFilter GROUP BY time($interval)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "count"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "sum"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "hostname",
+                  "operator": "=~",
+                  "value": "/$server/"
+                },
+                {
+                  "condition": "AND",
+                  "key": "http_status",
+                  "operator": "=",
+                  "value": "2xx"
+                }
+              ]
+            },
+            {
+              "alias": "1xx",
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "count",
+              "groupBy": [
+                {
+                  "interval": "auto",
+                  "params": [
+                    "auto"
+                  ],
+                  "type": "time"
+                }
+              ],
+              "hide": false,
+              "interval": "",
+              "measurement": "openstack_keystone_http_response_times",
+              "policy": "default",
+              "query": "SELECT sum(\"count\") FROM \"openstack_keystone_http_response_times\" WHERE \"hostname\" =~ /$server/ AND \"http_status\" = '1xx' AND $timeFilter GROUP BY time($interval)",
+              "rawQuery": false,
+              "refId": "B",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "count"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "sum"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "hostname",
+                  "operator": "=~",
+                  "value": "/$server/"
+                },
+                {
+                  "condition": "AND",
+                  "key": "http_status",
+                  "operator": "=",
+                  "value": "1xx"
+                }
+              ]
+            },
+            {
+              "alias": "3xx",
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "count",
+              "groupBy": [
+                {
+                  "interval": "auto",
+                  "params": [
+                    "auto"
+                  ],
+                  "type": "time"
+                }
+              ],
+              "hide": false,
+              "interval": "",
+              "measurement": "openstack_keystone_http_response_times",
+              "policy": "default",
+              "query": "SELECT sum(\"count\") FROM \"openstack_keystone_http_response_times\" WHERE \"hostname\" =~ /$server/ AND \"http_status\" = '3xx' AND $timeFilter GROUP BY time($interval)",
+              "rawQuery": false,
+              "refId": "C",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "count"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "sum"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "hostname",
+                  "operator": "=~",
+                  "value": "/$server/"
+                },
+                {
+                  "condition": "AND",
+                  "key": "http_status",
+                  "operator": "=",
+                  "value": "3xx"
+                }
+              ]
+            },
+            {
+              "alias": "4xx",
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "count",
+              "groupBy": [
+                {
+                  "interval": "auto",
+                  "params": [
+                    "auto"
+                  ],
+                  "type": "time"
+                }
+              ],
+              "hide": false,
+              "interval": "",
+              "measurement": "openstack_keystone_http_response_times",
+              "policy": "default",
+              "query": "SELECT sum(\"count\") FROM \"openstack_keystone_http_response_times\" WHERE \"hostname\" =~ /$server/ AND \"http_status\" = '4xx' AND $timeFilter GROUP BY time($interval)",
+              "rawQuery": false,
+              "refId": "D",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "count"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "sum"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "hostname",
+                  "operator": "=~",
+                  "value": "/$server/"
+                },
+                {
+                  "condition": "AND",
+                  "key": "http_status",
+                  "operator": "=",
+                  "value": "4xx"
+                }
+              ]
+            },
+            {
+              "alias": "5xx",
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "count",
+              "groupBy": [
+                {
+                  "interval": "auto",
+                  "params": [
+                    "auto"
+                  ],
+                  "type": "time"
+                }
+              ],
+              "hide": false,
+              "interval": "",
+              "measurement": "openstack_keystone_http_response_times",
+              "policy": "default",
+              "query": "SELECT sum(\"count\") FROM \"openstack_keystone_http_response_times\" WHERE \"hostname\" =~ /$server/ AND \"http_status\" = '5xx' AND $timeFilter GROUP BY time($interval)",
+              "rawQuery": false,
+              "refId": "E",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "count"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "sum"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "hostname",
+                  "operator": "=~",
+                  "value": "/$server/"
+                },
+                {
+                  "condition": "AND",
+                  "key": "http_status",
+                  "operator": "=",
+                  "value": "5xx"
+                }
+              ]
+            }
+          ],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Number of HTTP responses on $server",
+          "tooltip": {
+            "msResolution": false,
+            "shared": true,
+            "value_type": "individual"
+          },
+          "type": "graph",
+          "xaxis": {
+            "show": true
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "logBase": 1,
+              "max": null,
+              "min": 0,
+              "show": true
+            },
+            {
+              "format": "short",
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        }
+      ],
+      "showTitle": true,
+      "title": "Service Status"
+    },
+    {
+      "collapse": false,
+      "editable": true,
+      "height": "100px",
+      "panels": [
+        {
+          "content": "<br />\n<h3 align=\"center\"> Up </h3>",
+          "editable": true,
+          "error": false,
+          "id": 15,
+          "links": [],
+          "mode": "html",
+          "span": 2,
+          "style": {},
+          "title": "",
+          "type": "text"
+        },
+        {
+          "cacheTimeout": null,
+          "colorBackground": false,
+          "colorValue": false,
+          "colors": [
+            "rgba(245, 54, 54, 0.9)",
+            "rgba(237, 129, 40, 0.89)",
+            "rgba(50, 172, 45, 0.97)"
+          ],
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "format": "none",
+          "gauge": {
+            "maxValue": 100,
+            "minValue": 0,
+            "show": false,
+            "thresholdLabels": false,
+            "thresholdMarkers": true
+          },
+          "id": 16,
+          "interval": ">60s",
+          "links": [],
+          "maxDataPoints": 100,
+          "nullPointMode": "connected",
+          "nullText": null,
+          "postfix": "",
+          "postfixFontSize": "50%",
+          "prefix": "",
+          "prefixFontSize": "50%",
+          "span": 2,
+          "sparkline": {
+            "fillColor": "rgba(31, 118, 189, 0.18)",
+            "full": false,
+            "lineColor": "rgb(31, 120, 193)",
+            "show": false
+          },
+          "targets": [
+            {
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "mean",
+              "groupBy": [
+                {
+                  "params": [
+                    "$interval"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "null"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "groupByTags": [],
+              "measurement": "haproxy_backend_servers",
+              "policy": "default",
+              "query": "SELECT last(\"value\") FROM \"haproxy_backend_servers\" WHERE \"environment_label\" =~ /^$environment$/ AND \"backend\" = 'keystone_public_api' AND \"state\" = 'up' AND $timeFilter GROUP BY time($interval) fill(null)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "value"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "last"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "environment_label",
+                  "operator": "=",
+                  "value": "$environment"
+                },
+                {
+                  "key": "backend",
+                  "value": "keystone_public_api"
+                },
+                {
+                  "condition": "AND",
+                  "key": "state",
+                  "value": "up"
+                }
+              ]
+            }
+          ],
+          "thresholds": "",
+          "title": "Public",
+          "type": "singlestat",
+          "valueFontSize": "80%",
+          "valueMaps": [
+            {
+              "op": "=",
+              "text": "N/A",
+              "value": "null"
+            }
+          ],
+          "valueName": "current"
+        },
+        {
+          "cacheTimeout": null,
+          "colorBackground": false,
+          "colorValue": false,
+          "colors": [
+            "rgba(245, 54, 54, 0.9)",
+            "rgba(237, 129, 40, 0.89)",
+            "rgba(50, 172, 45, 0.97)"
+          ],
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "format": "none",
+          "gauge": {
+            "maxValue": 100,
+            "minValue": 0,
+            "show": false,
+            "thresholdLabels": false,
+            "thresholdMarkers": true
+          },
+          "id": 17,
+          "interval": ">60s",
+          "links": [],
+          "maxDataPoints": 100,
+          "nullPointMode": "connected",
+          "nullText": null,
+          "postfix": "",
+          "postfixFontSize": "50%",
+          "prefix": "",
+          "prefixFontSize": "50%",
+          "span": 2,
+          "sparkline": {
+            "fillColor": "rgba(31, 118, 189, 0.18)",
+            "full": false,
+            "lineColor": "rgb(31, 120, 193)",
+            "show": false
+          },
+          "targets": [
+            {
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "mean",
+              "groupBy": [
+                {
+                  "params": [
+                    "$interval"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "null"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "groupByTags": [],
+              "measurement": "haproxy_backend_servers",
+              "policy": "default",
+              "query": "SELECT last(\"value\") FROM \"haproxy_backend_servers\" WHERE \"environment_label\" =~ /^$environment$/ AND \"backend\" = 'keystone_admin_api' AND \"state\" = 'up' AND $timeFilter GROUP BY time($interval) fill(null)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "value"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "last"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "environment_label",
+                  "operator": "=",
+                  "value": "$environment"
+                },
+                {
+                  "key": "backend",
+                  "value": "keystone_admin_api"
+                },
+                {
+                  "condition": "AND",
+                  "key": "state",
+                  "value": "up"
+                }
+              ]
+            }
+          ],
+          "thresholds": "",
+          "title": "Admin",
+          "type": "singlestat",
+          "valueFontSize": "80%",
+          "valueMaps": [
+            {
+              "op": "=",
+              "text": "N/A",
+              "value": "null"
+            }
+          ],
+          "valueName": "current"
+        },
+        {
+          "content": "",
+          "editable": true,
+          "error": false,
+          "id": 18,
+          "links": [],
+          "mode": "markdown",
+          "span": 6,
+          "style": {},
+          "title": "",
+          "type": "text"
+        },
+        {
+          "content": "<br />\n<h3 align=\"center\"> Down </h3>",
+          "editable": true,
+          "error": false,
+          "id": 19,
+          "links": [],
+          "mode": "html",
+          "span": 2,
+          "style": {},
+          "title": "",
+          "type": "text"
+        },
+        {
+          "cacheTimeout": null,
+          "colorBackground": false,
+          "colorValue": true,
+          "colors": [
+            "rgba(255, 255, 255, 0.97)",
+            "rgba(255, 255, 255, 0.89)",
+            "rgba(245, 54, 54, 0.9)"
+          ],
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "format": "none",
+          "gauge": {
+            "maxValue": 100,
+            "minValue": 0,
+            "show": false,
+            "thresholdLabels": false,
+            "thresholdMarkers": true
+          },
+          "id": 20,
+          "interval": ">60s",
+          "links": [],
+          "maxDataPoints": 100,
+          "nullPointMode": "connected",
+          "nullText": null,
+          "postfix": "",
+          "postfixFontSize": "50%",
+          "prefix": "",
+          "prefixFontSize": "50%",
+          "span": 2,
+          "sparkline": {
+            "fillColor": "rgba(31, 118, 189, 0.18)",
+            "full": false,
+            "lineColor": "rgb(31, 120, 193)",
+            "show": false
+          },
+          "targets": [
+            {
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "mean",
+              "groupBy": [
+                {
+                  "params": [
+                    "$interval"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "null"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "groupByTags": [],
+              "measurement": "haproxy_backend_servers",
+              "policy": "default",
+              "query": "SELECT last(\"value\") FROM \"haproxy_backend_servers\" WHERE \"environment_label\" =~ /^$environment$/ AND \"backend\" = 'keystone_public_api' AND \"state\" = 'down' AND $timeFilter GROUP BY time($interval) fill(null)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "value"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "last"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "environment_label",
+                  "operator": "=",
+                  "value": "$environment"
+                },
+                {
+                  "key": "backend",
+                  "value": "keystone_public_api"
+                },
+                {
+                  "condition": "AND",
+                  "key": "state",
+                  "value": "down"
+                }
+              ]
+            }
+          ],
+          "thresholds": "0,1",
+          "title": "",
+          "type": "singlestat",
+          "valueFontSize": "80%",
+          "valueMaps": [
+            {
+              "op": "=",
+              "text": "N/A",
+              "value": "null"
+            }
+          ],
+          "valueName": "current"
+        },
+        {
+          "cacheTimeout": null,
+          "colorBackground": false,
+          "colorValue": true,
+          "colors": [
+            "rgba(255, 255, 255, 0.97)",
+            "rgba(255, 255, 255, 0.89)",
+            "rgba(245, 54, 54, 0.9)"
+          ],
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "format": "none",
+          "gauge": {
+            "maxValue": 100,
+            "minValue": 0,
+            "show": false,
+            "thresholdLabels": false,
+            "thresholdMarkers": true
+          },
+          "id": 21,
+          "interval": ">60s",
+          "links": [],
+          "maxDataPoints": 100,
+          "nullPointMode": "connected",
+          "nullText": null,
+          "postfix": "",
+          "postfixFontSize": "50%",
+          "prefix": "",
+          "prefixFontSize": "50%",
+          "span": 2,
+          "sparkline": {
+            "fillColor": "rgba(31, 118, 189, 0.18)",
+            "full": false,
+            "lineColor": "rgb(31, 120, 193)",
+            "show": false
+          },
+          "targets": [
+            {
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "mean",
+              "groupBy": [
+                {
+                  "params": [
+                    "$interval"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "null"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "groupByTags": [],
+              "measurement": "haproxy_backend_servers",
+              "policy": "default",
+              "query": "SELECT last(\"value\") FROM \"haproxy_backend_servers\" WHERE \"environment_label\" =~ /^$environment$/ AND \"backend\" = 'keystone_admin_api' AND \"state\" = 'down' AND $timeFilter GROUP BY time($interval) fill(null)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "value"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "last"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "environment_label",
+                  "operator": "=",
+                  "value": "$environment"
+                },
+                {
+                  "key": "backend",
+                  "value": "keystone_admin_api"
+                },
+                {
+                  "condition": "AND",
+                  "key": "state",
+                  "value": "down"
+                }
+              ]
+            }
+          ],
+          "thresholds": "0,1",
+          "title": "",
+          "type": "singlestat",
+          "valueFontSize": "80%",
+          "valueMaps": [
+            {
+              "op": "=",
+              "text": "N/A",
+              "value": "null"
+            }
+          ],
+          "valueName": "current"
+        },
+        {
+          "content": "",
+          "editable": true,
+          "error": false,
+          "id": 22,
+          "links": [],
+          "mode": "markdown",
+          "span": 6,
+          "style": {},
+          "title": "",
+          "type": "text"
+        }
+      ],
+      "showTitle": true,
+      "title": "Keystone API"
+    },
+    {
+      "collapse": false,
+      "editable": true,
+      "height": "250px",
+      "panels": [
+        {
+          "cacheTimeout": null,
+          "colorBackground": false,
+          "colorValue": false,
+          "colors": [
+            "rgba(245, 54, 54, 0.9)",
+            "rgba(237, 129, 40, 0.89)",
+            "rgba(50, 172, 45, 0.97)"
+          ],
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "format": "none",
+          "gauge": {
+            "maxValue": 100,
+            "minValue": 0,
+            "show": false,
+            "thresholdLabels": false,
+            "thresholdMarkers": true
+          },
+          "id": 12,
+          "interval": "> 60s",
+          "links": [],
+          "maxDataPoints": 100,
+          "nullPointMode": "connected",
+          "nullText": null,
+          "postfix": "",
+          "postfixFontSize": "50%",
+          "prefix": "",
+          "prefixFontSize": "50%",
+          "span": 2,
+          "sparkline": {
+            "fillColor": "rgba(31, 118, 189, 0.18)",
+            "full": false,
+            "lineColor": "rgb(31, 120, 193)",
+            "show": false
+          },
+          "targets": [
+            {
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "last",
+              "groupBy": [
+                {
+                  "params": [
+                    "$interval"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "null"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "groupByTags": [],
+              "measurement": "openstack_keystone_users",
+              "policy": "default",
+              "query": "SELECT last(\"value\") FROM \"openstack_keystone_users\" WHERE \"environment_label\" =~ /^$environment$/ AND \"state\" = 'enabled' AND $timeFilter GROUP BY time($interval) fill(null)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "value"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "last"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "environment_label",
+                  "operator": "=",
+                  "value": "$environment"
+                },
+                {
+                  "key": "state",
+                  "value": "enabled"
+                }
+              ]
+            }
+          ],
+          "thresholds": "",
+          "title": "Users",
+          "type": "singlestat",
+          "valueFontSize": "80%",
+          "valueMaps": [
+            {
+              "op": "=",
+              "text": "N/A",
+              "value": "null"
+            }
+          ],
+          "valueName": "current"
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "datasource": null,
+          "decimals": 0,
+          "editable": true,
+          "error": false,
+          "fill": 0,
+          "grid": {
+            "threshold1": null,
+            "threshold1Color": "rgba(216, 200, 27, 0.27)",
+            "threshold2": null,
+            "threshold2Color": "rgba(234, 112, 112, 0.22)"
+          },
+          "id": 23,
+          "interval": "> 60s",
+          "legend": {
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": false,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "connected",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "span": 10,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "alias": "number of users",
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "last",
+              "groupBy": [
+                {
+                  "interval": "auto",
+                  "params": [
+                    "auto"
+                  ],
+                  "type": "time"
+                }
+              ],
+              "measurement": "openstack_keystone_users",
+              "policy": "default",
+              "query": "SELECT last(\"value\") FROM \"openstack_keystone_users\" WHERE \"environment_label\" =~ /^$environment$/ AND \"state\" = 'enabled' AND $timeFilter GROUP BY time($interval)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "value"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "last"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "environment_label",
+                  "operator": "=",
+                  "value": "$environment"
+                },
+                {
+                  "key": "state",
+                  "operator": "=",
+                  "value": "enabled"
+                }
+              ]
+            }
+          ],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "",
+          "tooltip": {
+            "msResolution": false,
+            "shared": true,
+            "value_type": "cumulative"
+          },
+          "type": "graph",
+          "xaxis": {
+            "show": true
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": "",
+              "logBase": 1,
+              "max": null,
+              "min": 0,
+              "show": true
+            },
+            {
+              "format": "short",
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        },
+        {
+          "cacheTimeout": null,
+          "colorBackground": false,
+          "colorValue": false,
+          "colors": [
+            "rgba(245, 54, 54, 0.9)",
+            "rgba(237, 129, 40, 0.89)",
+            "rgba(50, 172, 45, 0.97)"
+          ],
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "format": "none",
+          "gauge": {
+            "maxValue": 100,
+            "minValue": 0,
+            "show": false,
+            "thresholdLabels": false,
+            "thresholdMarkers": true
+          },
+          "id": 11,
+          "interval": "> 60s",
+          "links": [],
+          "maxDataPoints": 100,
+          "nullPointMode": "connected",
+          "nullText": null,
+          "postfix": "",
+          "postfixFontSize": "50%",
+          "prefix": "",
+          "prefixFontSize": "50%",
+          "span": 2,
+          "sparkline": {
+            "fillColor": "rgba(31, 118, 189, 0.18)",
+            "full": false,
+            "lineColor": "rgb(31, 120, 193)",
+            "show": false
+          },
+          "targets": [
+            {
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "last",
+              "groupBy": [
+                {
+                  "params": [
+                    "$interval"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "null"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "groupByTags": [],
+              "measurement": "openstack_keystone_tenants",
+              "policy": "default",
+              "query": "SELECT last(\"value\") FROM \"openstack_keystone_tenants\" WHERE \"environment_label\" =~ /^$environment$/ AND \"state\" = 'enabled' AND $timeFilter GROUP BY time($interval) fill(null)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "value"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "last"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "environment_label",
+                  "operator": "=",
+                  "value": "$environment"
+                },
+                {
+                  "key": "state",
+                  "value": "enabled"
+                }
+              ]
+            }
+          ],
+          "thresholds": "",
+          "title": "Tenants",
+          "type": "singlestat",
+          "valueFontSize": "80%",
+          "valueMaps": [
+            {
+              "op": "=",
+              "text": "N/A",
+              "value": "null"
+            }
+          ],
+          "valueName": "current"
+        },
+        {
+          "aliasColors": {},
+          "bars": false,
+          "datasource": null,
+          "decimals": 0,
+          "editable": true,
+          "error": false,
+          "fill": 0,
+          "grid": {
+            "threshold1": null,
+            "threshold1Color": "rgba(216, 200, 27, 0.27)",
+            "threshold2": null,
+            "threshold2Color": "rgba(234, 112, 112, 0.22)"
+          },
+          "id": 24,
+          "interval": "> 60s",
+          "legend": {
+            "avg": false,
+            "current": false,
+            "max": false,
+            "min": false,
+            "show": false,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 1,
+          "links": [],
+          "nullPointMode": "connected",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "span": 10,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "alias": "number of tenants",
+              "column": "value",
+              "dsType": "influxdb",
+              "function": "last",
+              "groupBy": [
+                {
+                  "params": [
+                    "$interval"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "0"
+                  ],
+                  "type": "fill"
+                }
+              ],
+              "groupByTags": [],
+              "measurement": "openstack_keystone_tenants",
+              "policy": "default",
+              "query": "SELECT last(\"value\") FROM \"openstack_keystone_tenants\" WHERE \"environment_label\" =~ /^$environment$/ AND \"state\" = 'enabled' AND $timeFilter GROUP BY time($interval) fill(0)",
+              "rawQuery": false,
+              "refId": "A",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "params": [
+                      "value"
+                    ],
+                    "type": "field"
+                  },
+                  {
+                    "params": [],
+                    "type": "last"
+                  }
+                ]
+              ],
+              "tags": [
+                {
+                  "key": "environment_label",
+                  "operator": "=",
+                  "value": "$environment"
+                },
+                {
+                  "key": "state",
+                  "value": "enabled"
+                }
+              ]
+            }
+          ],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "",
+          "tooltip": {
+            "msResolution": false,
+            "shared": true,
+            "value_type": "cumulative"
+          },
+          "type": "graph",
+          "xaxis": {
+            "show": true
+          },
+          "yaxes": [
+            {
+              "format": "short",
+              "label": "",
+              "logBase": 1,
+              "max": null,
+              "min": 0,
+              "show": true
+            },
+            {
+              "format": "short",
+              "logBase": 1,
+              "max": null,
+              "min": null,
+              "show": true
+            }
+          ]
+        }
+      ],
+      "showTitle": true,
+      "title": "Resources"
+    }
+  ],
+  "schemaVersion": 12,
+  "sharedCrosshair": true,
+  "style": "dark",
+  "tags": [],
+  "templating": {
+    "enable": true,
+    "list": [
+      {
+        "allFormat": "regex values",
+        "current": {},
+        "datasource": null,
+        "hide": 0,
+        "includeAll": false,
+        "name": "environment",
+        "options": [],
+        "query": "show tag values from cpu_idle with key = environment_label",
+        "refresh": 1,
+        "refresh_on_load": true,
+        "regex": "",
+        "type": "query"
+      },
+      {
+        "allFormat": "regex values",
+        "current": {},
+        "datasource": null,
+        "hide": 0,
+        "includeAll": true,
+        "name": "server",
+        "options": [],
+        "query": "show tag values from openstack_keystone_http_response_times with key = hostname where environment_label =~ /^$environment$/",
+        "refresh": 1,
+        "refresh_on_load": true,
+        "regex": "",
+        "type": "query"
+      }
+    ]
+  },
+  "time": {
+    "from": "now-1h",
+    "to": "now"
+  },
+  "timepicker": {
+    "collapse": false,
+    "enable": true,
+    "notice": false,
+    "now": true,
+    "refresh_intervals": [
+      "5s",
+      "10s",
+      "30s",
+      "1m",
+      "5m",
+      "15m",
+      "30m",
+      "1h",
+      "2h",
+      "1d"
+    ],
+    "status": "Stable",
+    "time_options": [
+      "5m",
+      "15m",
+      "1h",
+      "6h",
+      "12h",
+      "24h",
+      "2d",
+      "7d",
+      "30d"
+    ],
+    "type": "timepicker"
+  },
+  "timezone": "browser",
+  "title": "Keystone",
+  "version": 2
+}
diff --git a/keystone/files/heka.toml b/keystone/files/heka.toml
index 6ddcadc..cfca158 100644
--- a/keystone/files/heka.toml
+++ b/keystone/files/heka.toml
@@ -1,22 +1,13 @@
-{%- if pillar.keystone.server is defined %}
 [logstreamer_keystone]
 type = "LogstreamerInput"
 log_directory = "/var/log/keystone"
-file_match = 'keystone\.log\.?(?P<Index>\d+)?(.gz)?'
+file_match = '(?P<Service>.+)\.log\.?(?P<Index>\d*)?(.gz)?'
+differentiator = ['keystone','_','Service']
 priority = ["^Index"]
-decoder = "keystone"
+decoder = "openstack"
 oldest_duration = "168h"
 
-[logstreamer_keystone_manage]
-type = "LogstreamerInput"
-log_directory = "/var/log/keystone"
-file_match = 'keystone-manage\.log\.?(?P<Index>\d+)?(.gz)?'
-priority = ["^Index"]
-decoder = "keystone"
-oldest_duration = "168h"
-
-[keystone]
+[openstack]
 type = "SandboxDecoder"
 filename = "lua_modules/decoders/openstack.lua"
 module_directory = "/usr/share/heka/lua_modules;/usr/share/heka/lua_modules/common"
-{% endif %}
diff --git a/keystone/files/juno/wsgi-keystone.conf b/keystone/files/juno/wsgi-keystone.conf
new file mode 100644
index 0000000..d542a87
--- /dev/null
+++ b/keystone/files/juno/wsgi-keystone.conf
@@ -0,0 +1,8 @@
+WSGIScriptAlias /keystone/main  /var/www/cgi-bin/keystone/main
+WSGIScriptAlias /keystone/admin  /var/www/cgi-bin/keystone/admin
+
+<Location "/keystone">
+ NSSRequireSSL
+ Authtype none
+</Location>
+
diff --git a/keystone/files/keystonerc b/keystone/files/keystonerc
index 3a1ca5f..ee35efc 100644
--- a/keystone/files/keystonerc
+++ b/keystone/files/keystonerc
@@ -3,5 +3,6 @@
 export OS_PASSWORD={{ server.admin_password }}
 export OS_TENANT_NAME={{ server.admin_tenant }}
 export OS_AUTH_URL=http://{{ server.bind.private_address }}:{{ server.bind.private_port }}/v2.0
+export OS_REGION_NAME={{ server.region }}
 export OS_SERVICE_TOKEN={{ server.service_token }}
 export OS_SERVICE_ENDPOINT="http://{{ server.bind.private_address }}:{{ server.bind.private_port }}/v2.0/"
diff --git a/keystone/files/keystonerc_user b/keystone/files/keystonerc_user
index 62293bf..61f6e67 100644
--- a/keystone/files/keystonerc_user
+++ b/keystone/files/keystonerc_user
@@ -11,4 +11,3 @@
 export OS_SERVICE_ENDPOINT="http://{{ provider.host }}:{{ provider.port }}/{{ provider.get('version', 'v2.0') }}/"
 {%- endif %}
 export OS_AUTH_STRATEGY=keystone
-	
\ No newline at end of file
diff --git a/keystone/files/keystonercv3 b/keystone/files/keystonercv3
index 9566528..c9deae7 100644
--- a/keystone/files/keystonercv3
+++ b/keystone/files/keystonercv3
@@ -6,4 +6,5 @@
 export OS_PROJECT_NAME={{ server.admin_tenant }}
 export OS_TENANT_NAME={{ server.admin_tenant }}
 export OS_USERNAME={{ server.admin_name }}
-export OS_PASSWORD={{ server.admin_password }}
\ No newline at end of file
+export OS_PASSWORD={{ server.admin_password }}
+export OS_REGION_NAME={{ server.region }}
diff --git a/keystone/files/kilo/keystone.conf.Debian b/keystone/files/kilo/keystone.conf.Debian
index 11ae0f2..0e59b15 100644
--- a/keystone/files/kilo/keystone.conf.Debian
+++ b/keystone/files/kilo/keystone.conf.Debian
@@ -97,6 +97,7 @@
 # notification has the same information, as well as information about the
 # initiator of the event. Valid options are: basic and cadf (string value)
 #notification_format = basic
+notification_format = {{ server.get("notification_format", "basic") }}
 
 #
 # From keystone.openstack.common.eventlet_backdoor
@@ -697,7 +698,7 @@
 # key. Increasing this value means that additional secondary keys will be kept
 # in the rotation. (integer value)
 #max_active_keys = 3
-
+max_active_keys={{ server.tokens.get('max_active_keys', '3') }}
 
 [identity]
 
diff --git a/keystone/files/kilo/wsgi-keystone.conf b/keystone/files/kilo/wsgi-keystone.conf
new file mode 100644
index 0000000..c6a8214
--- /dev/null
+++ b/keystone/files/kilo/wsgi-keystone.conf
@@ -0,0 +1,38 @@
+{%- from "keystone/map.jinja" import server with context %}
+{%- set site = salt['pillar.get']('apache:server:site:'+site_name) %}
+Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000
+Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:35357
+
+<VirtualHost {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000>
+{%- include "apache/files/_name.conf" %}
+{%- include "apache/files/_ssl.conf" %}
+{%- include "apache/files/_locations.conf" %}
+
+    WSGIDaemonProcess keystone-public processes=5 threads=1 user=keystone display-name=%{GROUP}
+    WSGIProcessGroup keystone-public
+    WSGIScriptAlias / /var/www/cgi-bin/keystone/main
+    WSGIApplicationGroup %{GLOBAL}
+    WSGIPassAuthorization On
+    <IfVersion >= 2.4>
+      ErrorLogFormat "%{cu}t %M"
+    </IfVersion>
+{%- include "apache/files/_log.conf" %}
+</VirtualHost>
+
+<VirtualHost {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:35357>
+{%- include "apache/files/_name.conf" %}
+{%- include "apache/files/_ssl.conf" %}
+{%- include "apache/files/_locations.conf" %}
+
+    WSGIDaemonProcess keystone-admin processes=5 threads=1 user=keystone display-name=%{GROUP}
+    WSGIProcessGroup keystone-admin
+    WSGIScriptAlias / /var/www/cgi-bin/keystone/admin
+    WSGIApplicationGroup %{GLOBAL}
+    WSGIPassAuthorization On
+    <IfVersion >= 2.4>
+      ErrorLogFormat "%{cu}t %M"
+    </IfVersion>
+    ErrorLog /var/log/apache2/keystone.log
+    CustomLog /var/log/apache2/keystone_access.log combined
+{%- include "apache/files/_log.conf" %}
+</VirtualHost>
diff --git a/keystone/files/liberty/keystone.conf.Debian b/keystone/files/liberty/keystone.conf.Debian
index 80c1ed6..e52f532 100644
--- a/keystone/files/liberty/keystone.conf.Debian
+++ b/keystone/files/liberty/keystone.conf.Debian
@@ -93,6 +93,7 @@
 # initiator of the event. (string value)
 # Allowed values: basic, cadf
 #notification_format = basic
+notification_format = {{ server.get("notification_format", "basic") }}
 
 #
 # From oslo.log
@@ -300,6 +301,11 @@
 # Allowed authentication methods. (list value)
 #methods = external,password,token,oauth1
 
+{% if server.websso is defined %}
+methods = external,password,token,{{ server.websso.protocol }}
+{{ server.websso.protocol }} = keystone.auth.plugins.mapped.Mapped
+{%- endif %}
+
 # Entrypoint for the password auth plugin module in the keystone.auth.password
 # namespace. (string value)
 #password = <None>
@@ -317,6 +323,10 @@
 # namespace. (string value)
 #oauth1 = <None>
 
+{% if server.websso is defined %}
+[{{ server.websso.protocol }}]
+remote_id_attribute = {{ server.websso.remote_id_attribute }}
+{%- endif %}
 
 [cache]
 
@@ -779,6 +789,9 @@
 # Entrypoint for the federation backend driver in the keystone.federation
 # namespace. (string value)
 #driver = sql
+{% if server.websso is defined %}
+driver = {{ server.websso.federation_driver }}
+{%- endif %}
 
 # Value to be used when filtering assertion parameters from the environment.
 # (string value)
@@ -801,6 +814,13 @@
 # example: trusted_dashboard=http://acme.com trusted_dashboard=http://beta.com
 # (multi valued)
 #trusted_dashboard =
+{%- if server.websso is defined %}
+{%- if server.websso.trusted_dashboard is defined %}
+{%- for dashboard in server.websso.trusted_dashboard %}
+trusted_dashboard = {{ dashboard }}
+{%- endfor %}
+{%- endif %}
+{%- endif %}
 
 # Location of Single Sign-On callback handler, will return a token to a trusted
 # dashboard host. (string value)
@@ -823,7 +843,7 @@
 # key. Increasing this value means that additional secondary keys will be kept
 # in the rotation. (integer value)
 #max_active_keys = 3
-
+max_active_keys={{ server.tokens.get('max_active_keys', '3') }}
 
 [identity]
 
diff --git a/keystone/files/liberty/wsgi-keystone.conf b/keystone/files/liberty/wsgi-keystone.conf
new file mode 100644
index 0000000..beaf74b
--- /dev/null
+++ b/keystone/files/liberty/wsgi-keystone.conf
@@ -0,0 +1,92 @@
+{%- from "keystone/map.jinja" import server with context %}
+{%- set site = salt['pillar.get']('apache:server:site:'+site_name) %}
+Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000
+Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:35357
+
+<VirtualHost {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000>
+{%- include "apache/files/_name.conf" %}
+{%- include "apache/files/_ssl.conf" %}
+{%- include "apache/files/_locations.conf" %}
+
+    WSGIDaemonProcess keystone-public processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP}
+    WSGIProcessGroup keystone-public
+    WSGIScriptAlias / /usr/bin/keystone-wsgi-public
+    WSGIApplicationGroup %{GLOBAL}
+    WSGIPassAuthorization On
+    ErrorLogFormat "%{cu}t %M"
+{%- include "apache/files/_log.conf" %}
+
+    <Directory /usr/bin>
+      Require all granted
+    </Directory>
+
+    {% if server.websso is defined %}
+    WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-public/$1
+    <Location /Shibboleth.sso>
+      SetHandler shib
+    </Location>
+    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    {%- endif %}
+
+</VirtualHost>
+
+<VirtualHost {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:35357>
+{%- include "apache/files/_name.conf" %}
+{%- include "apache/files/_ssl.conf" %}
+{%- include "apache/files/_locations.conf" %}
+
+    WSGIDaemonProcess keystone-admin processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP}
+    WSGIProcessGroup keystone-admin
+    WSGIScriptAlias / /usr/bin/keystone-wsgi-admin
+    WSGIApplicationGroup %{GLOBAL}
+    WSGIPassAuthorization On
+    ErrorLogFormat "%{cu}t %M"
+{%- include "apache/files/_log.conf" %}
+
+    <Directory /usr/bin>
+      Require all granted
+    </Directory>
+
+    {% if server.websso is defined %}
+    WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-admin/$1
+    <Location /Shibboleth.sso>
+      SetHandler shib
+    </Location>
+    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    {%- endif %}
+
+</VirtualHost>
diff --git a/keystone/files/mitaka/keystone.conf.Debian b/keystone/files/mitaka/keystone.conf.Debian
index 9f80fd9..06b84c2 100644
--- a/keystone/files/mitaka/keystone.conf.Debian
+++ b/keystone/files/mitaka/keystone.conf.Debian
@@ -104,6 +104,7 @@
 # initiator of the event. (string value)
 # Allowed values: basic, cadf
 #notification_format = basic
+notification_format = {{ server.get("notification_format", "basic") }}
 
 # Define the notification options to opt-out from. The value expected is:
 # identity.<resource_type>.<operation>. This field can be set multiple times in
@@ -354,6 +355,11 @@
 # Allowed authentication methods. (list value)
 #methods = external,password,token,oauth1
 
+{% if server.websso is defined %}
+methods = external,password,token,{{ server.websso.protocol }}
+{{ server.websso.protocol }} = keystone.auth.plugins.mapped.Mapped
+{%- endif %}
+
 # Entrypoint for the password auth plugin module in the keystone.auth.password
 # namespace. (string value)
 #password = <None>
@@ -371,6 +377,10 @@
 # namespace. (string value)
 #oauth1 = <None>
 
+{% if server.websso is defined %}
+[{{ server.websso.protocol }}]
+remote_id_attribute = {{ server.websso.remote_id_attribute }}
+{%- endif %}
 
 [cache]
 
@@ -833,6 +843,9 @@
 # Entrypoint for the federation backend driver in the keystone.federation
 # namespace. (string value)
 #driver = sql
+{% if server.websso is defined %}
+driver = {{ server.websso.federation_driver }}
+{%- endif %}
 
 # Value to be used when filtering assertion parameters from the environment.
 # (string value)
@@ -855,6 +868,13 @@
 # example: trusted_dashboard=http://acme.com/auth/websso
 # trusted_dashboard=http://beta.com/auth/websso (multi valued)
 #trusted_dashboard =
+{%- if server.websso is defined %}
+{%- if server.websso.trusted_dashboard is defined %}
+{%- for dashboard in server.websso.trusted_dashboard %}
+trusted_dashboard = {{ dashboard }}
+{%- endfor %}
+{%- endif %}
+{%- endif %}
 
 # Location of Single Sign-On callback handler, will return a token to a trusted
 # dashboard host. (string value)
@@ -877,7 +897,7 @@
 # key. Increasing this value means that additional secondary keys will be kept
 # in the rotation. (integer value)
 #max_active_keys = 3
-
+max_active_keys={{ server.tokens.get('max_active_keys', '3') }}
 
 [identity]
 
@@ -2169,4 +2189,4 @@
 #driver = sql
 
 [extra_headers]
-Distribution = Ubuntu
\ No newline at end of file
+Distribution = Ubuntu
diff --git a/keystone/files/mitaka/wsgi-keystone.conf b/keystone/files/mitaka/wsgi-keystone.conf
new file mode 100644
index 0000000..b82c820
--- /dev/null
+++ b/keystone/files/mitaka/wsgi-keystone.conf
@@ -0,0 +1,130 @@
+{%- from "keystone/map.jinja" import server with context %}
+{%- set site = salt['pillar.get']('apache:server:site:'+site_name) %}
+Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000
+Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:35357
+
+<VirtualHost {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000>
+{%- include "apache/files/_name.conf" %}
+{%- include "apache/files/_ssl.conf" %}
+{%- include "apache/files/_locations.conf" %}
+
+    WSGIDaemonProcess keystone-public processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP}
+    WSGIProcessGroup keystone-public
+    WSGIScriptAlias / /usr/local/bin/keystone-wsgi-public
+    WSGIApplicationGroup %{GLOBAL}
+    WSGIPassAuthorization On
+    LimitRequestBody 114688
+    <IfVersion >= 2.4>
+      ErrorLogFormat "%{cu}t %M"
+    </IfVersion>
+{%- include "apache/files/_log.conf" %}
+
+    <Directory /usr/local/bin>
+        <IfVersion >= 2.4>
+            Require all granted
+        </IfVersion>
+        <IfVersion < 2.4>
+            Order allow,deny
+            Allow from all
+        </IfVersion>
+    </Directory>
+
+    {% if server.websso is defined %}
+    WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-public/$1
+    <Location /Shibboleth.sso>
+      SetHandler shib
+    </Location>
+    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    {%- endif %}
+
+</VirtualHost>
+
+<VirtualHost {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:35357>
+{%- include "apache/files/_name.conf" %}
+{%- include "apache/files/_ssl.conf" %}
+{%- include "apache/files/_locations.conf" %}
+
+    WSGIDaemonProcess keystone-admin processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP}
+    WSGIProcessGroup keystone-admin
+    WSGIScriptAlias / /usr/local/bin/keystone-wsgi-admin
+    WSGIApplicationGroup %{GLOBAL}
+    WSGIPassAuthorization On
+    LimitRequestBody 114688
+    <IfVersion >= 2.4>
+      ErrorLogFormat "%{cu}t %M"
+    </IfVersion>
+{%- include "apache/files/_log.conf" %}
+
+    <Directory /usr/local/bin>
+        <IfVersion >= 2.4>
+            Require all granted
+        </IfVersion>
+        <IfVersion < 2.4>
+            Order allow,deny
+            Allow from all
+        </IfVersion>
+    </Directory>
+
+    {% if server.websso is defined %}
+    WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-admin/$1
+    <Location /Shibboleth.sso>
+      SetHandler shib
+    </Location>
+    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    {%- endif %}
+
+</VirtualHost>
+
+Alias /identity /usr/local/bin/keystone-wsgi-public
+<Location /identity>
+    SetHandler wsgi-script
+    Options +ExecCGI
+
+    WSGIProcessGroup keystone-public
+    WSGIApplicationGroup %{GLOBAL}
+    WSGIPassAuthorization On
+</Location>
+
+Alias /identity_admin /usr/local/bin/keystone-wsgi-admin
+<Location /identity_admin>
+    SetHandler wsgi-script
+    Options +ExecCGI
+
+    WSGIProcessGroup keystone-admin
+    WSGIApplicationGroup %{GLOBAL}
+    WSGIPassAuthorization On
+</Location>
diff --git a/keystone/files/salt-minion.conf b/keystone/files/salt-minion.conf
new file mode 100644
index 0000000..19c5af9
--- /dev/null
+++ b/keystone/files/salt-minion.conf
@@ -0,0 +1,15 @@
+{%- if pillar.keystone.get('server', {'enabled': False}).enabled -%}
+{%- from "keystone/map.jinja" import server with context -%}
+keystone.token: '{{ server.service_token }}'
+keystone.endpoint: 'http://{{ server.bind.address }}:{{ server.bind.private_port }}/v2.0'
+{%- else -%}
+{%- from "keystone/map.jinja" import client with context -%}
+keystone.user: '{{ client.server.user }}'
+keystone.password: '{{ client.server.password }}'
+keystone.tenant: '{{ client.server.tenant }}'
+keystone.auth_url: 'http://{{ client.server.host }}:{{ client.server.public_port }}/v2.0/'
+{%- endif %}
+
+{#-
+vim: syntax=jinja
+-#}
diff --git a/keystone/files/sso_callback_template.html b/keystone/files/sso_callback_template.html
new file mode 100644
index 0000000..c6997dc
--- /dev/null
+++ b/keystone/files/sso_callback_template.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Keystone WebSSO redirect</title>
+  </head>
+  <body>
+     <form id="sso" name="sso" action="$host" method="post">
+       Please wait...
+       <br/>
+       <input type="hidden" name="token" id="token" value="$token"/>
+       <noscript>
+         <input type="submit" name="submit_no_javascript" id="submit_no_javascript"
+            value="If your JavaScript is disabled, please click to continue"/>
+       </noscript>
+     </form>
+     <script type="text/javascript">
+       window.onload = function() {
+         document.forms['sso'].submit();
+       }
+     </script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/keystone/map.jinja b/keystone/map.jinja
index 31c1c49..284130f 100644
--- a/keystone/map.jinja
+++ b/keystone/map.jinja
@@ -1,7 +1,7 @@
 
 {% set server = salt['grains.filter_by']({
     'Debian': {
-        'pkgs': ['keystone', 'python-keystone', 'python-keystoneclient', 'python-psycopg2', 'python-mysqldb', 'mysql-client', 'python-six', 'python-memcache', 'python-openstackclient'],
+        'pkgs': ['keystone', 'python-keystone', 'python-keystoneclient', 'python-psycopg2', 'python-mysqldb', 'mysql-client', 'python-six', 'python-memcache', 'python-openstackclient', 'gettext-base', 'python-pycadf'],
         'service_name': 'keystone',
         'version': 'icehouse',
         'api_version': '2',
@@ -13,7 +13,7 @@
         'roles': ['admin', 'Member']
     },
     'RedHat': {
-        'pkgs': ['openstack-keystone', 'openstack-utils', 'python-keystone', 'python-keystoneclient'],
+        'pkgs': ['openstack-keystone', 'openstack-utils', 'python-keystone', 'python-keystoneclient', 'python-pycadf'],
         'service_name': 'openstack-keystone',
         'api_version': '2',
         'version': 'icehouse',
@@ -24,7 +24,7 @@
         'notification': False,
         'roles': ['admin', 'Member']
     },
-}, merge=salt['pillar.get']('keystone:server')) %}
+}, merge=pillar.keystone.get('server', {})) %}
 
 {% set client = salt['grains.filter_by']({
     'Debian': {
@@ -36,7 +36,7 @@
         'pkgs': ['python-keystoneclient'],
         'roles': ['admin', 'Member'],
     },
-}, merge=salt['pillar.get']('keystone:client')) %}
+}, merge=pillar.keystone.get('client', {})) %}
 
 {% set control = salt['grains.filter_by']({
     'Debian': {
@@ -45,4 +45,4 @@
     'RedHat': {
         'pkgs': [],
     },
-}, merge=salt['pillar.get']('keystone:control')) %}
+}, merge=pillar.keystone.get('control', {})) %}
diff --git a/keystone/meta/collectd.yml b/keystone/meta/collectd.yml
new file mode 100644
index 0000000..01e5e79
--- /dev/null
+++ b/keystone/meta/collectd.yml
@@ -0,0 +1,28 @@
+{%- from "keystone/map.jinja" import server with context %}
+{%- if server.get('enabled', False) %}
+local_plugin:
+  collectd_check_local_endpoint:
+    endpoint:
+      keystone-public-api:
+        expected_code: 300
+        url: "http://{{ server.bind.address|replace('0.0.0.0', '127.0.0.1') }}:{{ server.bind.public_port }}/"
+      keystone-admin-api:
+        expected_code: 300
+        url: "http://{{ server.bind.address|replace('0.0.0.0', '127.0.0.1') }}:{{ server.bind.private_port }}/"
+
+remote_plugin:
+  openstack_keystone:
+    plugin: python
+    template: keystone/files/collectd_openstack_keystone.conf
+    url: "http://{{ server.bind.public_address }}:{{ server.bind.public_port }}/v{% if server.get('api_version', 2)|int == 2 %}2.0{% else %}3{% endif %}"
+    username: {{ server.admin_name }}
+    password: {{ server.admin_password }}
+    tenant: {{ server.admin_tenant }}
+  check_openstack_api:
+    plugin: python
+    template: keystone/files/collectd_check_openstack_api.conf
+    url: "http://{{ server.bind.public_address }}:{{ server.bind.public_port }}/v{% if server.get('api_version', 2)|int == 2 %}2.0{% else %}3{% endif %}"
+    username: {{ server.admin_name }}
+    password: {{ server.admin_password }}
+    tenant: {{ server.admin_tenant }}
+{%- endif %}
diff --git a/keystone/meta/config.yml b/keystone/meta/config.yml
new file mode 100644
index 0000000..79ebc05
--- /dev/null
+++ b/keystone/meta/config.yml
@@ -0,0 +1,13 @@
+config:
+  {%- if pillar.keystone.server is defined %}
+  {%- from "keystone/map.jinja" import server with context %}
+  keystone.conf:
+    source: "salt://keystone/files/{{ server.version }}/keystone.conf.{{ grains.os_family|default('Debian') }}"
+    template: jinja
+  keystone-paste.ini:
+    source: "salt://keystone/files/{{ server.version }}/keystone-paste.ini.{{ grains.os_family|default('Debian') }}"
+    template: jinja
+  policy.json:
+    source: "salt://keystone/files/{{ server.version }}/policy-v{{ server.api_version }}.json"
+    template: jinja
+  {%- endif %}
\ No newline at end of file
diff --git a/keystone/meta/grafana.yml b/keystone/meta/grafana.yml
new file mode 100644
index 0000000..c0bd17f
--- /dev/null
+++ b/keystone/meta/grafana.yml
@@ -0,0 +1,4 @@
+dashboard:
+  keystone:
+    format: json
+    template: keystone/files/grafana_dashboards/keystone_influxdb.json
diff --git a/keystone/meta/heka.yml b/keystone/meta/heka.yml
new file mode 100644
index 0000000..d046938
--- /dev/null
+++ b/keystone/meta/heka.yml
@@ -0,0 +1,163 @@
+{%- if pillar.keystone.server is defined %}
+log_collector:
+  decoder:
+    keystone:
+      engine: sandbox
+      module_file: /usr/share/lma_collector/decoders/openstack_log.lua
+      module_dir: /usr/share/lma_collector/common;/usr/share/heka/lua_modules
+      adjust_timezone: true
+  splitter:
+    keystone:
+      engine: token
+      delimiter: '\n'
+  input:
+    keystone_log:
+      engine: logstreamer
+      log_directory: "/var/log"
+      file_match: 'keystone/(?P<Service>.+)\.log\.?(?P<Seq>\d*)$'
+      differentiator: ['keystone', '_', 'Service']
+      priority: ["^Seq"]
+      decoder: "keystone_decoder"
+      splitter: "keystone_splitter"
+metric_collector:
+  trigger:
+    keystone_response_time_duration:
+      description: 'Keystone API is too slow'
+      severity: warning
+      no_data_policy: okay
+      rules:
+      - metric: openstack_keystone_http_response_times
+        field:
+          http_method: '== GET || == POST'
+          http_status: '!= 5xx'
+        relational_operator: '>'
+        threshold: 0.3
+        window: 60
+        periods: 0
+        value: upper_90
+        function: max
+    keystone_logs_error:
+      description: 'Too many errors have been detected in Keystone logs'
+      severity: warning
+      no_data_policy: okay
+      rules:
+      - metric: log_messages
+        field:
+          service: keystone
+          level: error
+        relational_operator: '>'
+        threshold: 0.1
+        window: 70
+        periods: 0
+        function: max
+    keystone_public_api_local_endpoint:
+      description: 'Keystone public API is locally down'
+      severity: down
+      rules:
+      - metric: openstack_check_local_api
+        field:
+          service: keystone-public-api
+        relational_operator: '=='
+        threshold: 0
+        window: 60
+        periods: 0
+        function: last
+  alarm:
+    keystone_response_time:
+      alerting: enabled
+      triggers:
+      - keystone_response_time_duration
+      dimension:
+        service: keystone-response-time
+    keystone_logs:
+      alerting: enabled
+      triggers:
+      - keystone_logs_error
+      dimension:
+        service: keystone-logs
+    keystone_public_api_endpoint:
+      alerting: enabled
+      triggers:
+      - keystone_public_api_local_endpoint
+      dimension:
+        service: keystone-public-api-endpoint
+remote_collector:
+  trigger:
+    keystone_public_api_check_failed:
+      description: 'Endpoint check for keystone-public-api is failed'
+      severity: down
+      rules:
+      - metric: openstack_check_api
+        field:
+          service: keystone-public-api
+        relational_operator: '=='
+        threshold: 0
+        window: 60
+        periods: 0
+        function: last
+  alarm:
+    keystone_public_api_check:
+      alerting: enabled
+      triggers:
+      - keystone_public_api_check_failed
+      dimension:
+        service: keystone-public-api-check
+aggregator:
+  alarm_cluster:
+    keystone_response_time:
+      policy: status_of_members
+      alerting: enabled
+      group_by: hostname
+      match:
+        service: keystone-response-time
+      members:
+      - keystone_response_time
+      dimension:
+        service: keystone
+        nagios_host: 01-service-clusters
+    keystone_logs:
+      policy: status_of_members
+      alerting: enabled
+      group_by: hostname
+      match:
+        service: keystone-logs
+      members:
+      - keystone_logs
+      dimension:
+        service: keystone
+        nagios_host: 01-service-clusters
+    keystone_public_api_endpoint:
+      policy: availability_of_members
+      alerting: enabled
+      group_by: hostname
+      match:
+        service: keystone-public-api-endpoint
+      members:
+      - keystone_public_api_endpoint
+      dimension:
+        service: keystone
+        nagios_host: 01-service-clusters
+    keystone_public_api_check:
+      policy: highest_severity
+      alerting: enabled
+      match:
+        service: keystone-public-api-check
+      members:
+      - keystone_public_api_check
+      dimension:
+        service: keystone
+        nagios_host: 01-service-clusters
+    keystone:
+      policy: highest_severity
+      alerting: enabled_with_notification
+      match:
+        service: keystone
+      members:
+      - keystone_response_time
+      - keystone_logs
+      - keystone_public_api_endpoint
+      - keystone_public_api_check
+      dimension:
+        cluster_name: keystone
+        nagios_host: 00-top-clusters
+{%- endif %}
diff --git a/keystone/meta/salt.yml b/keystone/meta/salt.yml
new file mode 100644
index 0000000..c5f5e3a
--- /dev/null
+++ b/keystone/meta/salt.yml
@@ -0,0 +1,9 @@
+orchestrate:
+  server:
+    priority: 500
+    batch: 1
+  client:
+    priority: 510
+  control:
+    priority: 520
+
diff --git a/keystone/meta/sensu.yml b/keystone/meta/sensu.yml
index 045a6dc..c032762 100644
--- a/keystone/meta/sensu.yml
+++ b/keystone/meta/sensu.yml
@@ -1,6 +1,6 @@
 check:
   local_keystone_server_proc:
-    command: "PATH=$PATH:/usr/lib64/nagios/plugins:/usr/lib/nagios/plugins check_procs -C keystone-all -u keystone -c 1:20"
+    command: "PATH=$PATH:/usr/lib64/nagios/plugins:/usr/lib/nagios/plugins check_procs -C keystone-all -u keystone -c 1:1024"
     interval: 60
     occurrences: 1
     subscribers:
diff --git a/keystone/server.sls b/keystone/server.sls
index 311b4b0..cf54fb4 100644
--- a/keystone/server.sls
+++ b/keystone/server.sls
@@ -5,6 +5,30 @@
   pkg.installed:
   - names: {{ server.pkgs }}
 
+{%- if server.service_name in ['apache2', 'httpd'] %}
+include:
+- apache
+
+{%- if grains.os_family == "Debian" %}
+keystone:
+{%- endif %}
+{%- if grains.os_family == "RedHat" %}
+openstack-keystone:
+{%- endif %}
+  service.dead:
+    - enable: False
+    - watch:
+      - pkg: keystone_packages
+
+{%- endif %}
+
+keystone_salt_config:
+  file.managed:
+    - name: /etc/salt/minion.d/keystone.conf
+    - template: jinja
+    - source: salt://keystone/files/salt-minion.conf
+    - mode: 600
+
 {%- if not salt['user.info']('keystone') %}
 
 keystone_user:
@@ -35,7 +59,20 @@
   - template: jinja
   - require:
     - pkg: keystone_packages
+  - watch_in:
+    - service: keystone_service
 
+{% if server.websso is defined %}
+
+/etc/keystone/sso_callback_template.html:
+  file.managed:
+  - source: salt://keystone/files/sso_callback_template.html
+  - require:
+    - pkg: keystone_packages
+  - watch_in:
+    - service: keystone_service
+
+{%- endif %}
 
 /etc/keystone/keystone-paste.ini:
   file.managed:
@@ -43,16 +80,20 @@
   - template: jinja
   - require:
     - pkg: keystone_packages
+  {%- if not grains.get('noservices', False) %}
   - watch_in:
     - service: keystone_service
+  {%- endif %}
 
 /etc/keystone/policy.json:
   file.managed:
   - source: salt://keystone/files/{{ server.version }}/policy-v{{ server.api_version }}.json
   - require:
     - pkg: keystone_packages
+  {%- if not grains.get('noservices', False) %}
   - watch_in:
     - service: keystone_service
+  {%- endif %}
 
 {%- if server.get("domain", {}) %}
 
@@ -70,8 +111,10 @@
     - template: jinja
     - require:
       - file: /etc/keystone/domains
+    {%- if not grains.get('noservices', False) %}
     - watch_in:
       - service: keystone_service
+    {%- endif %}
     - defaults:
         domain_name: {{ domain_name }}
 
@@ -83,11 +126,14 @@
     - contents_pillar: keystone:server:domain:{{ domain_name }}:ldap:tls:cacert
     - require:
       - file: /etc/keystone/domains
+    {%- if not grains.get('noservices', False) %}
     - watch_in:
       - service: keystone_service
+    {%- endif %}
 
 {%- endif %}
 
+{%- if not grains.get('noservices', False) %}
 keystone_domain_{{ domain_name }}:
   cmd.run:
     - name: source /root/keystonercv3 && openstack domain create --description "{{ domain.description }}" {{ domain_name }}
@@ -95,6 +141,7 @@
     - require:
       - file: /root/keystonercv3
       - service: keystone_service
+{%- endif %}
 
 {%- endfor %}
 
@@ -108,17 +155,30 @@
     - contents_pillar: keystone:server:ldap:tls:cacert
     - require:
       - pkg: keystone_packages
+    {%- if not grains.get('noservices', False) %}
     - watch_in:
       - service: keystone_service
+    {%- endif %}
 
 {%- endif %}
 
+{%- if not grains.get('noservices', False) %}
 keystone_service:
   service.running:
   - name: {{ server.service_name }}
   - enable: True
   - watch:
     - file: /etc/keystone/keystone.conf
+{%- endif %}
+
+{%- if grains.get('virtual_subtype', None) == "Docker" %}
+keystone_entrypoint:
+  file.managed:
+  - name: /entrypoint.sh
+  - template: jinja
+  - source: salt://keystone/files/entrypoint.sh
+  - mode: 755
+{%- endif %}
 
 /root/keystonerc:
   file.managed:
@@ -134,11 +194,13 @@
   - require:
     - pkg: keystone_packages
 
+{%- if not grains.get('noservices', False) %}
 keystone_syncdb:
   cmd.run:
-  - name: keystone-manage db_sync
+  - name: keystone-manage db_sync; sleep 1
   - require:
     - service: keystone_service
+{%- endif %}
 
 {% if server.tokens.engine == 'fernet' %}
 
@@ -153,30 +215,43 @@
   - require_in:
     - service: keystone_fernet_setup
 
+{%- if not grains.get('noservices', False) %}
 keystone_fernet_setup:
   cmd.run:
   - name: keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone
   - require:
     - service: keystone_service
     - file: keystone_fernet_keys
+{%- endif %}
 
 {% endif %}
 
+{%- if not grains.get('noservices', False) %}
+
+{%- if not salt['pillar.get']('linux:system:repo:mirantis_openstack', False) %}
+
 keystone_service_tenant:
   keystone.tenant_present:
   - name: {{ server.service_tenant }}
+  - connection_token: {{ server.service_token }}
+  - connection_endpoint: 'http://{{ server.bind.address }}:{{ server.bind.private_port }}/v2.0'
   - require:
     - cmd: keystone_syncdb
+    - file: keystone_salt_config
 
 keystone_admin_tenant:
   keystone.tenant_present:
   - name: {{ server.admin_tenant }}
+  - connection_token: {{ server.service_token }}
+  - connection_endpoint: 'http://{{ server.bind.address }}:{{ server.bind.private_port }}/v2.0'
   - require:
     - keystone: keystone_service_tenant
 
 keystone_roles:
   keystone.role_present:
   - names: {{ server.roles }}
+  - connection_token: {{ server.service_token }}
+  - connection_endpoint: 'http://{{ server.bind.address }}:{{ server.bind.private_port }}/v2.0'
   - require:
     - keystone: keystone_service_tenant
 
@@ -189,17 +264,23 @@
   - roles:
       {{ server.admin_tenant }}:
       - admin
+  - connection_token: {{ server.service_token }}
+  - connection_endpoint: 'http://{{ server.bind.address }}:{{ server.bind.private_port }}/v2.0'
   - require:
     - keystone: keystone_admin_tenant
     - keystone: keystone_roles
 
-{% for service_name, service in server.get('service', {}).iteritems() %}
+{%- endif %}
+
+{%- for service_name, service in server.get('service', {}).iteritems() %}
 
 keystone_{{ service_name }}_service:
   keystone.service_present:
   - name: {{ service_name }}
   - service_type: {{ service.type }}
   - description: {{ service.description }}
+  - connection_token: {{ server.service_token }}
+  - connection_endpoint: 'http://{{ server.bind.address }}:{{ server.bind.private_port }}/v2.0'
   - require:
     - keystone: keystone_roles
 
@@ -210,8 +291,11 @@
   - internalurl: '{{ service.bind.get('internal_protocol', 'http') }}://{{ service.bind.internal_address }}:{{ service.bind.internal_port }}{{ service.bind.internal_path }}'
   - adminurl: '{{ service.bind.get('admin_protocol', 'http') }}://{{ service.bind.admin_address }}:{{ service.bind.admin_port }}{{ service.bind.admin_path }}'
   - region: {{ service.get('region', 'RegionOne') }}
+  - connection_token: {{ server.service_token }}
+  - connection_endpoint: 'http://{{ server.bind.address }}:{{ server.bind.private_port }}/v2.0'
   - require:
     - keystone: keystone_{{ service_name }}_service
+    - file: keystone_salt_config
 
 {% if service.user is defined %}
 
@@ -224,18 +308,22 @@
   - roles:
       {{ server.service_tenant }}:
       - admin
+  - connection_token: {{ server.service_token }}
+  - connection_endpoint: 'http://{{ server.bind.address }}:{{ server.bind.private_port }}/v2.0'
   - require:
     - keystone: keystone_roles
 
 {% endif %}
 
-{% endfor %}
+{%- endfor %}
 
 {%- for tenant_name, tenant in server.get('tenant', {}).iteritems() %}
 
 keystone_tenant_{{ tenant_name }}:
   keystone.tenant_present:
   - name: {{ tenant_name }}
+  - connection_token: {{ server.service_token }}
+  - connection_endpoint: 'http://{{ server.bind.address }}:{{ server.bind.private_port }}/v2.0'
   - require:
     - keystone: keystone_roles
 
@@ -254,11 +342,14 @@
       {%- else %}
       - Member
       {%- endif %}
+  - connection_token: {{ server.service_token }}
+  - connection_endpoint: 'http://{{ server.bind.address }}:{{ server.bind.private_port }}/v2.0'
   - require:
     - keystone: keystone_tenant_{{ tenant_name }}
 
 {%- endfor %}
 
 {%- endfor %}
+{%- endif %} {# end noservices #}
 
 {%- endif %}
diff --git a/metadata/service/server/cluster.yml b/metadata/service/server/cluster.yml
index d01af2c..5038cf3 100644
--- a/metadata/service/server/cluster.yml
+++ b/metadata/service/server/cluster.yml
@@ -3,8 +3,6 @@
 classes:
 - service.keystone.support
 parameters:
-  _param:
-    mysql_keystone_password: password
   keystone:
     server:
       enabled: true
@@ -42,10 +40,10 @@
         ha_queues: true
       cache:
         engine: memcached
-        members: 
+        members:
         - host: ${_param:cluster_node01_address}
           port: 11211
         - host: ${_param:cluster_node02_address}
           port: 11211
         - host: ${_param:cluster_node03_address}
-          port: 11211
\ No newline at end of file
+          port: 11211
diff --git a/metadata/service/server/container.yml b/metadata/service/server/container.yml
new file mode 100644
index 0000000..e421dbd
--- /dev/null
+++ b/metadata/service/server/container.yml
@@ -0,0 +1,44 @@
+parameters:
+  kubernetes:
+    control:
+      configmap:
+        keystone-server:
+          grains:
+            os_family: Debian
+          pillar:
+            keystone:
+              server:
+                enabled: true
+                version: ${_param:keystone_version}
+                service_token: ${_param:keystone_service_token}
+                service_tenant: service
+                admin_tenant: admin
+                admin_name: admin
+                admin_password: ${_param:keystone_admin_password}
+                admin_email: root@localhost
+                bind:
+                  address: 0.0.0.0
+                  private_address: ${_param:keystone_service_host}
+                  private_port: 35357
+                  public_address: ${_param:keystone_service_host}
+                  public_port: 5000
+                region: RegionOne
+                database:
+                  engine: mysql
+                  host: ${_param:mysql_service_host}
+                  port: 3306
+                  name: 'keystone'
+                  password: '${_param:mysql_keystone_password}'
+                  user: 'keystone'
+                tokens:
+                  engine: fernet
+                  expiration: 43200
+                  location: /var/lib/keystone/fernet-keys/
+                message_queue:
+                  engine: rabbitmq
+                  host: ${_param:rabbitmq_service_host}
+                  port: 5672
+                  user: openstack
+                  password: ${_param:rabbitmq_openstack_password}
+                  virtual_host: '/openstack'
+                  ha_queues: true
diff --git a/metadata/service/server/single.yml b/metadata/service/server/single.yml
index 3e72a88..5269121 100644
--- a/metadata/service/server/single.yml
+++ b/metadata/service/server/single.yml
@@ -40,6 +40,6 @@
         ha_queues: true
       cache:
         engine: memcached
-        members: 
+        members:
         - host: localhost
-          port: 11211
\ No newline at end of file
+          port: 11211
diff --git a/metadata/service/support.yml b/metadata/service/support.yml
index 1c21fb8..283ca7e 100644
--- a/metadata/service/support.yml
+++ b/metadata/service/support.yml
@@ -2,10 +2,14 @@
   keystone:
     _support:
       collectd:
-        enabled: false
+        enabled: true
       heka:
         enabled: true
       sensu:
         enabled: true
       sphinx:
         enabled: true
+      config:
+        enabled: true
+      grafana:
+        enabled: true
diff --git a/tests/pillar/cluster.sls b/tests/pillar/cluster.sls
index da3d86d..d3538b9 100644
--- a/tests/pillar/cluster.sls
+++ b/tests/pillar/cluster.sls
@@ -26,6 +26,7 @@
       expiration: 86400
       location: /etc/keystone/fernet-keys/
     notification: true
+    notification_format: cadf
     message_queue:
       engine: rabbitmq
       host: 127.0.0.1
@@ -36,10 +37,10 @@
       ha_queues: true
     cache:
       engine: memcached
-      members: 
+      members:
       - host: 127.0.0.1
         port: 11211
       - host: 127.0.0.1
         port: 11211
       - host: 127.0.0.1
-        port: 11211
\ No newline at end of file
+        port: 11211
diff --git a/tests/pillar/single.sls b/tests/pillar/single.sls
index e81487c..3e7c49d 100644
--- a/tests/pillar/single.sls
+++ b/tests/pillar/single.sls
@@ -36,6 +36,6 @@
       location: /etc/keystone/fernet-keys/
     cache:
       engine: memcached
-      members: 
+      members:
       - host: localhost
-        port: 11211
\ No newline at end of file
+        port: 11211
diff --git a/tests/pillar/single_fernet.sls b/tests/pillar/single_fernet.sls
index 15f61f3..7077876 100644
--- a/tests/pillar/single_fernet.sls
+++ b/tests/pillar/single_fernet.sls
@@ -25,8 +25,9 @@
       engine: fernet
       expiration: 86400
       location: /etc/keystone/fernet-keys/
+      max_active_keys: 4
     cache:
       engine: memcached
-      members: 
+      members:
       - host: localhost
         port: 11211
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 3f42101..8c07e58 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -18,7 +18,7 @@
 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}"
+SALT_OPTS="${SALT_OPTS} --retcode-passthrough --local -c ${SALT_CONFIG_DIR} --log-file=/dev/null"
 
 if [ "x${SALT_VERSION}" != "x" ]; then
     PIP_SALT_VERSION="==${SALT_VERSION}"
@@ -64,6 +64,7 @@
 file_client: local
 cachedir: ${SALT_CACHE_DIR}
 verify_env: False
+minion_id_caching: False
 
 file_roots:
   base: