Merge pull request #6 from tcpcloud/stacklight

Stacklight
diff --git a/README.rst b/README.rst
index 89c289f..2a54f23 100644
--- a/README.rst
+++ b/README.rst
@@ -39,6 +39,38 @@
           port: 9200
 
 
+Client setup
+------------
+
+Client with host and port (Kibana use Elasticsearch to store its data):
+
+.. code-block:: yaml
+
+    kibana:
+      client:
+        enabled: true
+        server:
+          host: elasticsearch.host
+          port: 9200
+
+Client where you download a Kibana object that is stored in the directory
+*files/*:
+
+.. code-block:: yaml
+
+    kibana:
+      client:
+        enabled: true
+        server:
+          host: elasticsearch.host
+          port: 9200
+        object:
+          logs:
+            enabled: true
+            name: Logs
+            template: kibana/files/objects/dashboard_logs.json
+            type: 'dashboard'
+
 Read more
 =========
 
diff --git a/_states/kibana_object.py b/_states/kibana_object.py
new file mode 100644
index 0000000..ca0a133
--- /dev/null
+++ b/_states/kibana_object.py
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 -*-
+'''
+Manage Kibana objects.
+
+.. code-block:: yaml
+
+    kibana:
+      kibana_url: 'https://es.host.com:9200'
+      kibana_index: '.kibana'
+
+.. code-block:: yaml
+
+    Ensure minimum dashboard is managed:
+      kibana_objects.present:
+        - name: 'Logs'
+        - kibana_content: <JSON object>
+        - kibana_type: 'dashboard'
+
+'''
+
+# Import Python libs
+import requests
+
+# Import Salt libs
+from salt.utils.dictdiffer import DictDiffer
+
+
+def __virtual__():
+    '''Always load the module.'''
+    return True
+
+
+def present(name, kibana_content=None, kibana_type=None):
+    '''
+    Ensure the Kibana object exists in the database.
+
+    name
+        Name of the object
+
+    kibana_content
+        Content in JSON
+
+    kibana_type
+        String
+    '''
+    ret = {'name': name, 'result': True, 'comment': '', 'changes': {}}
+
+    if not kibana_content:
+        ret['result'] = False
+        ret['comment'] = 'Content is not set'
+        return ret
+
+    profile = __salt__['config.option']('kibana')
+
+    url, index = _set_parameters(name, kibana_type, profile)
+    if not url:
+        ret['result'] = False
+        ret['comment'] = index
+        return ret
+
+    try:
+        headers = {'Content-type': 'application/json'}
+        response = requests.put(url, headers=headers, json=kibana_content)
+    except requests.exceptions.RequestException as exc:
+        ret['result'] = False
+        ret['comment'] = ("Failed to create Kibana object {0}\n"
+                          "Got exception: {1}").format(name, exc)
+    else:
+        if response.ok:
+            ret['comment'] = 'Kibana object {0} has been created'.format(name)
+            ret['changes']['new'] = 'Kibana objects created'
+        else:
+            ret['result'] = False
+            ret['comment'] = ("Failed to post Kibana object {0}\n"
+                              "Response: {1}").format(name, response)
+
+    return ret
+
+
+def absent(name, kibana_type=None):
+    '''
+    Ensure the Kibana object is not present in the database.
+
+    name
+        Name of the object
+
+    kibana_type
+        String
+    '''
+    ret = {'name': name, 'result': True, 'comment': '', 'changes': {}}
+
+    profile = __salt__['config.option']('kibana')
+
+    url, index = _set_parameters(name, kibana_type, profile)
+    if not url:
+        ret['result'] = False
+        ret['comment'] = index
+        return ret
+
+    try:
+        response = requests.delete(url)
+    except requests.exceptions.RequestException as exc:
+        ret['result'] = False
+        ret['comment'] = ("Failed to delete Kibana object {0}\n"
+                          "Got exception: {1}").format(name, exc)
+    else:
+        if response.ok:
+            ret['comment'] = "Kibana object {0} has been deleted".format(name)
+        elif response.status_code == 404:
+            ret['comment'] = "Kibana object {0} was not present".format(name)
+        else:
+            ret['result'] = False
+            ret['comment'] = ("Failed to delete Kibana object {0}\n"
+                              "Response: {1}").format(name, response)
+
+    return ret
+
+
+def _set_parameters(name, kibana_type, profile):
+    '''
+    Retrieve parameters from profile.
+    '''
+
+    if not kibana_type:
+        return False, 'Type is not set'
+
+    url = profile.get('kibana_url')
+    if not url:
+        return False, 'Cannot get URL needed by Kibana client'
+
+    index = profile.get('kibana_index')
+    if not index:
+        return False, 'Cannot get the index needed by Kibana client'
+
+    url = "http://{0}/{1}/{2}/{3}".format(url, index, kibana_type, name)
+    return url, index
diff --git a/kibana/client.sls b/kibana/client.sls
new file mode 100644
index 0000000..95f0063
--- /dev/null
+++ b/kibana/client.sls
@@ -0,0 +1,24 @@
+{%- from "kibana/map.jinja" import client with context %}
+{%- if client.get('enabled', False) %}
+
+/etc/salt/minion.d/_kibana.conf:
+  file.managed:
+  - source: salt://kibana/files/_kibana.conf
+  - template: jinja
+  - user: root
+  - group: root
+
+{%- for object_name, object in client.get('object', {}).iteritems() %}
+kibana_object_{{ object_name }}:
+  {%- if object.get('enabled', False) %}
+  {% import_json object.template as content %}
+  kibana_object.present:
+  - kibana_content: {{ content|json }}
+  {%- else %}
+  kibana_object.absent:
+  {%- endif %}
+  - name: {{ object_name }}
+  - kibana_type: {{ object.type }}
+{%- endfor %}
+
+{%- endif %}
diff --git a/kibana/files/_kibana.conf b/kibana/files/_kibana.conf
new file mode 100644
index 0000000..410e2b2
--- /dev/null
+++ b/kibana/files/_kibana.conf
@@ -0,0 +1,5 @@
+{%- from "kibana/map.jinja" import client with context %}
+
+kibana:
+  kibana_url: {{ client.server.host }}:{{ client.server.port }}
+  kibana_index: {{ client.server.index }}
diff --git a/kibana/files/objects/config.json b/kibana/files/objects/config.json
new file mode 100644
index 0000000..e17715f
--- /dev/null
+++ b/kibana/files/objects/config.json
@@ -0,0 +1 @@
+{"buildNum" : 9892, "defaultIndex" : "log-*"}
diff --git a/kibana/files/objects/dashboard_logs.json b/kibana/files/objects/dashboard_logs.json
new file mode 100644
index 0000000..e3db200
--- /dev/null
+++ b/kibana/files/objects/dashboard_logs.json
@@ -0,0 +1,15 @@
+{
+  "title": "Logs",
+  "hits": 0,
+  "description": "",
+  "panelsJSON": "[{\"col\":1,\"columns\":[\"Hostname\",\"Logger\",\"programname\",\"severity_label\",\"Payload\",\"environment_label\"],\"id\":\"search-logs\",\"panelIndex\":5,\"row\":13,\"size_x\":12,\"size_y\":12,\"sort\":[\"Timestamp\",\"desc\"],\"type\":\"search\"},{\"col\":1,\"id\":\"NUMBER-OF-LOG-MESSAGES-PER-SEVERITY\",\"panelIndex\":7,\"row\":9,\"size_x\":4,\"size_y\":4,\"type\":\"visualization\"},{\"col\":7,\"id\":\"TOP-10-PROGRAMS\",\"panelIndex\":9,\"row\":5,\"size_x\":6,\"size_y\":4,\"type\":\"visualization\"},{\"col\":1,\"id\":\"LOG-MESSAGES-OVER-TIME-PER-SOURCE\",\"panelIndex\":10,\"row\":1,\"size_x\":6,\"size_y\":4,\"type\":\"visualization\"},{\"col\":5,\"id\":\"TOP-10-HOSTS\",\"panelIndex\":11,\"row\":9,\"size_x\":4,\"size_y\":4,\"type\":\"visualization\"},{\"col\":9,\"id\":\"NUMBER-OF-LOG-MESSAGES-PER-ROLE\",\"panelIndex\":12,\"row\":9,\"size_x\":4,\"size_y\":4,\"type\":\"visualization\"},{\"col\":1,\"id\":\"TOP-10-SOURCES\",\"panelIndex\":14,\"row\":5,\"size_x\":6,\"size_y\":4,\"type\":\"visualization\"},{\"col\":7,\"id\":\"LOG-MESSAGES-OVER-TIME-PER-SEVERITY\",\"panelIndex\":16,\"row\":1,\"size_x\":6,\"size_y\":4,\"type\":\"visualization\"}]",
+  "optionsJSON": "{\"darkTheme\":true}",
+  "uiStateJSON": "{\"P-10\":{\"vis\":{\"legendOpen\":true}},\"P-11\":{\"vis\":{\"colors\":{\"Count\":\"#629E51\"},\"legendOpen\":true}},\"P-12\":{\"spy\":{\"mode\":{\"fill\":false,\"name\":null}},\"vis\":{\"colors\":{\"Count\":\"#2F575E\"},\"legendOpen\":false}},\"P-14\":{\"vis\":{\"legendOpen\":true}},\"P-7\":{\"vis\":{\"legendOpen\":false}},\"P-9\":{\"vis\":{\"colors\":{\"Count\":\"#99440A\"},\"legendOpen\":true}}}",
+  "version": 1,
+  "timeRestore": true,
+  "timeTo": "now",
+  "timeFrom": "now-1h",
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\"filter\":[{\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}}}]}"
+  }
+}
diff --git a/kibana/files/objects/dashboard_notifications.json b/kibana/files/objects/dashboard_notifications.json
new file mode 100644
index 0000000..201a203
--- /dev/null
+++ b/kibana/files/objects/dashboard_notifications.json
@@ -0,0 +1,15 @@
+{
+  "title": "Notifications",
+  "hits": 0,
+  "description": "",
+  "panelsJSON": "[{\"col\":1,\"columns\":[\"Logger\",\"publisher\",\"severity_label\",\"event_type\",\"old_state\",\"old_task_state\",\"state\",\"new_task_state\",\"environment_label\",\"display_name\"],\"id\":\"search-notifications\",\"panelIndex\":1,\"row\":14,\"size_x\":12,\"size_y\":11,\"sort\":[\"Timestamp\",\"desc\"],\"type\":\"search\"},{\"col\":1,\"id\":\"NOTIFICATIONS-OVER-TIME-PER-SOURCE\",\"panelIndex\":2,\"row\":1,\"size_x\":6,\"size_y\":4,\"type\":\"visualization\"},{\"col\":7,\"id\":\"NOTIFICATIONS-OVER-TIME-PER-SEVERITY\",\"panelIndex\":3,\"row\":1,\"size_x\":6,\"size_y\":4,\"type\":\"visualization\"},{\"col\":7,\"id\":\"EVENT-TYPE-BREAKDOWN\",\"panelIndex\":4,\"row\":5,\"size_x\":6,\"size_y\":5,\"type\":\"visualization\"},{\"col\":1,\"id\":\"SOURCE-BREAKDOWN\",\"panelIndex\":5,\"row\":5,\"size_x\":6,\"size_y\":5,\"type\":\"visualization\"},{\"col\":1,\"id\":\"HOST-BREAKDOWN\",\"panelIndex\":6,\"row\":10,\"size_x\":6,\"size_y\":4,\"type\":\"visualization\"},{\"col\":7,\"id\":\"NOTIFICATIONS-PER-SEVERITY\",\"panelIndex\":7,\"row\":10,\"size_x\":6,\"size_y\":4,\"type\":\"visualization\"}]",
+  "optionsJSON": "{\"darkTheme\":true}",
+  "uiStateJSON": "{\"P-4\":{\"vis\":{\"legendOpen\":true}},\"P-7\":{\"vis\":{\"legendOpen\":false}}}",
+  "version": 1,
+  "timeRestore": true,
+  "timeTo": "now",
+  "timeFrom": "now-1h",
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\"filter\":[{\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}}}]}"
+  }
+}
diff --git a/kibana/files/objects/index-pattern_logs.json b/kibana/files/objects/index-pattern_logs.json
new file mode 100644
index 0000000..432f1c9
--- /dev/null
+++ b/kibana/files/objects/index-pattern_logs.json
@@ -0,0 +1,2 @@
+{"title": "log-*", "timeFieldName" : "Timestamp", "fields" : "[{\"name\":\"openstack_release\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"openstack_roles\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"Type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"http_response_time\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"tenant_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"http_url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"Logger\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"severity_label\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"Severity\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"user_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"programname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"Pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"Hostname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"instance_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"Payload\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"http_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"http_response_size\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"deployment_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"Timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"http_method\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"http_status\",\"type\":\"conflict\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":true},{\"name\":\"python_module\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"syslogfacility\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"environment_label\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"http_client_ip_address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"openstack_region\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]"}
+
diff --git a/kibana/files/objects/index-pattern_notifications.json b/kibana/files/objects/index-pattern_notifications.json
new file mode 100644
index 0000000..84dc492
--- /dev/null
+++ b/kibana/files/objects/index-pattern_notifications.json
@@ -0,0 +1 @@
+{"title": "notification-*", "timeFieldName" : "Timestamp", "fields": "[{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"event_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"memory_mb\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"vcpus\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"old_task_state\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"severity_label\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"volume_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"Severity\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"terminated_at\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"image_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"Pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"instance_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"launched_at\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"hostname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"old_state\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"deployment_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"size\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"display_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"syslogfacility\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"new_task_state\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"environment_label\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"openstack_region\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"openstack_release\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"openstack_roles\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"Type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"openstack_role\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"state\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"tenant_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"Logger\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"publisher\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"created_at\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"programname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"user_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"Hostname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"instance_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"availability_zone\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"Payload\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"deleted_at\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"Timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"subnet_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"request_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"network_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"port_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"disk_gb\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]"}
diff --git a/kibana/files/objects/search_logs.json b/kibana/files/objects/search_logs.json
new file mode 100644
index 0000000..3da81d2
--- /dev/null
+++ b/kibana/files/objects/search_logs.json
@@ -0,0 +1,21 @@
+{
+  "title": "Logs",
+  "description": "",
+  "hits": 0,
+  "columns": [
+    "Hostname",
+    "Logger",
+    "programname",
+    "severity_label",
+    "Payload",
+    "environment_label"
+  ],
+  "sort": [
+    "Timestamp",
+    "desc"
+  ],
+  "version": 1,
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\"index\":\"log-*\",\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}},\"filter\":[],\"highlight\":{\"pre_tags\":[\"@kibana-highlighted-field@\"],\"post_tags\":[\"@/kibana-highlighted-field@\"],\"fields\":{\"*\":{}},\"require_field_match\":false,\"fragment_size\":2147483647}}"
+  }
+}
diff --git a/kibana/files/objects/search_notifications.json b/kibana/files/objects/search_notifications.json
new file mode 100644
index 0000000..47e9b87
--- /dev/null
+++ b/kibana/files/objects/search_notifications.json
@@ -0,0 +1,25 @@
+{
+  "title": "Notifications",
+  "description": "",
+  "hits": 0,
+  "columns": [
+    "Logger",
+    "publisher",
+    "severity_label",
+    "event_type",
+    "old_state",
+    "old_task_state",
+    "state",
+    "new_task_state",
+    "environment_label",
+    "display_name"
+  ],
+  "sort": [
+    "Timestamp",
+    "desc"
+  ],
+  "version": 1,
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\"index\":\"notification-*\",\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}},\"filter\":[],\"highlight\":{\"pre_tags\":[\"@kibana-highlighted-field@\"],\"post_tags\":[\"@/kibana-highlighted-field@\"],\"fields\":{\"*\":{}},\"require_field_match\":false,\"fragment_size\":2147483647}}"
+  }
+}
diff --git a/kibana/files/objects/visualization_EVENT-TYPE-BREAKDOWN.json b/kibana/files/objects/visualization_EVENT-TYPE-BREAKDOWN.json
new file mode 100644
index 0000000..0ccbcf7
--- /dev/null
+++ b/kibana/files/objects/visualization_EVENT-TYPE-BREAKDOWN.json
@@ -0,0 +1,10 @@
+{
+ "title": "EVENT TYPE BREAKDOWN",
+ "visState": "{\"title\":\"EVENT TYPE BREAKDOWN\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"scale\":\"linear\",\"mode\":\"grouped\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{\"customLabel\":\"\"}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"event_type\",\"size\":30,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "uiStateJSON": "{}",
+ "description": "",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+   "searchSourceJSON": "{\"index\":\"notification-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}"
+ }
+}
diff --git a/kibana/files/objects/visualization_HOST-BREAKDOWN.json b/kibana/files/objects/visualization_HOST-BREAKDOWN.json
new file mode 100644
index 0000000..71dc39d
--- /dev/null
+++ b/kibana/files/objects/visualization_HOST-BREAKDOWN.json
@@ -0,0 +1,10 @@
+{
+  "title": "HOST BREAKDOWN",
+  "visState": "{\"title\":\"HOST BREAKDOWN\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"Hostname\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"Hostname\"}},{\"id\":\"3\",\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"severity_label\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+  "uiStateJSON": "{}",
+  "description": "",
+  "version": 1,
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\"index\":\"notification-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}"
+  }
+}
diff --git a/kibana/files/objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SEVERITY.json b/kibana/files/objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SEVERITY.json
new file mode 100644
index 0000000..4ac44ec
--- /dev/null
+++ b/kibana/files/objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SEVERITY.json
@@ -0,0 +1,10 @@
+{
+  "title": "LOG MESSAGES OVER TIME PER SEVERITY",
+  "visState": "{\n  \"title\": \"LOG MESSAGES OVER TIME PER SEVERITY\",\n  \"type\": \"histogram\",\n  \"params\": {\n    \"shareYAxis\": true,\n    \"addTooltip\": true,\n    \"addLegend\": true,\n    \"scale\": \"linear\",\n    \"mode\": \"stacked\",\n    \"times\": [],\n    \"addTimeMarker\": false,\n    \"defaultYExtents\": false,\n    \"setYExtents\": false,\n    \"yAxis\": {}\n  },\n  \"aggs\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"count\",\n      \"schema\": \"metric\",\n      \"params\": {}\n    },\n    {\n      \"id\": \"2\",\n      \"type\": \"date_histogram\",\n      \"schema\": \"segment\",\n      \"params\": {\n        \"field\": \"Timestamp\",\n        \"interval\": \"auto\",\n        \"customInterval\": \"2h\",\n        \"min_doc_count\": 1,\n        \"extended_bounds\": {},\n        \"customLabel\": \"\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"type\": \"terms\",\n      \"schema\": \"group\",\n      \"params\": {\n        \"field\": \"severity_label\",\n        \"size\": 15,\n        \"order\": \"desc\",\n        \"orderBy\": \"1\"\n      }\n    }\n  ],\n  \"listeners\": {}\n}",
+  "uiStateJSON": "{\n  \"vis\": {\n    \"colors\": {\n      \"ERROR\": \"#BF1B00\",\n      \"EMERGENCY\": \"#99440A\",\n      \"WARNING\": \"#EF843C\",\n      \"INFO\": \"#7EB26C\",\n      \"DEBUG\": \"#1F78C1\",\n      \"NOTICE\": \"#6ED0E0\",\n      \"ALERT\": \"#1F78C1\"\n    }\n  }\n}",
+  "description": "",
+  "version": 1,
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\n  \"index\": \"log-*\",\n  \"query\": {\n    \"query_string\": {\n      \"query\": \"*\",\n      \"analyze_wildcard\": true\n    }\n  },\n  \"filter\": []\n}"
+  }
+}
diff --git a/kibana/files/objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SOURCE.json b/kibana/files/objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SOURCE.json
new file mode 100644
index 0000000..2ca7c05
--- /dev/null
+++ b/kibana/files/objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SOURCE.json
@@ -0,0 +1,10 @@
+{
+ "title": "LOG MESSAGES OVER TIME PER SOURCE",
+ "visState": "{\n  \"title\": \"LOG MESSAGES OVER TIME PER SOURCE\",\n  \"type\": \"histogram\",\n  \"params\": {\n    \"shareYAxis\": true,\n    \"addTooltip\": true,\n    \"addLegend\": true,\n    \"scale\": \"linear\",\n    \"mode\": \"stacked\",\n    \"times\": [],\n    \"addTimeMarker\": false,\n    \"defaultYExtents\": false,\n    \"setYExtents\": false,\n    \"yAxis\": {}\n  },\n  \"aggs\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"count\",\n      \"schema\": \"metric\",\n      \"params\": {}\n    },\n    {\n      \"id\": \"2\",\n      \"type\": \"date_histogram\",\n      \"schema\": \"segment\",\n      \"params\": {\n        \"field\": \"Timestamp\",\n        \"interval\": \"auto\",\n        \"customInterval\": \"2h\",\n        \"min_doc_count\": 1,\n        \"extended_bounds\": {},\n        \"customLabel\": \"\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"type\": \"terms\",\n      \"schema\": \"group\",\n      \"params\": {\n        \"field\": \"Logger\",\n        \"size\": 15,\n        \"order\": \"desc\",\n        \"orderBy\": \"1\"\n      }\n    }\n  ],\n  \"listeners\": {}\n}",
+ "uiStateJSON": "{}",
+ "description": "",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+   "searchSourceJSON": "{\n  \"index\": \"log-*\",\n  \"query\": {\n    \"query_string\": {\n      \"query\": \"*\",\n      \"analyze_wildcard\": true\n    }\n  },\n  \"filter\": []\n}"
+ }
+}
diff --git a/kibana/files/objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SEVERITY.json b/kibana/files/objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SEVERITY.json
new file mode 100644
index 0000000..7dfa485
--- /dev/null
+++ b/kibana/files/objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SEVERITY.json
@@ -0,0 +1,10 @@
+{
+  "title": "NOTIFICATIONS OVER TIME PER SEVERITY",
+  "visState": "{\"title\":\"NOTIFICATIONS OVER TIME PER SEVERITY\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"Timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"severity_label\",\"size\":20,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+  "uiStateJSON": "{\"vis\":{\"colors\":{\"ERROR\":\"#E24D42\"}}}",
+  "description": "",
+  "version": 1,
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\"index\":\"notification-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}"
+  }
+}
diff --git a/kibana/files/objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SOURCE.json b/kibana/files/objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SOURCE.json
new file mode 100644
index 0000000..98df8d5
--- /dev/null
+++ b/kibana/files/objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SOURCE.json
@@ -0,0 +1,10 @@
+{
+  "title": "NOTIFICATIONS OVER TIME PER SOURCE",
+  "visState": "{\n  \"title\": \"NOTIFICATIONS OVER TIME PER SOURCE\",\n  \"type\": \"histogram\",\n  \"params\": {\n    \"shareYAxis\": true,\n    \"addTooltip\": true,\n    \"addLegend\": true,\n    \"scale\": \"linear\",\n    \"mode\": \"stacked\",\n    \"times\": [],\n    \"addTimeMarker\": false,\n    \"defaultYExtents\": false,\n    \"setYExtents\": false,\n    \"yAxis\": {}\n  },\n  \"aggs\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"count\",\n      \"schema\": \"metric\",\n      \"params\": {}\n    },\n    {\n      \"id\": \"2\",\n      \"type\": \"date_histogram\",\n      \"schema\": \"segment\",\n      \"params\": {\n        \"field\": \"Timestamp\",\n        \"interval\": \"auto\",\n        \"customInterval\": \"2h\",\n        \"min_doc_count\": 1,\n        \"extended_bounds\": {}\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"type\": \"terms\",\n      \"schema\": \"group\",\n      \"params\": {\n        \"field\": \"Logger\",\n        \"size\": 20,\n        \"order\": \"desc\",\n        \"orderBy\": \"1\"\n      }\n    }\n  ],\n  \"listeners\": {}\n}",
+  "uiStateJSON": "{}",
+  "description": "",
+  "version": 1,
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\n  \"index\": \"notification-*\",\n  \"query\": {\n    \"query_string\": {\n      \"query\": \"*\",\n      \"analyze_wildcard\": true\n    }\n  },\n  \"filter\": []\n}"
+  }
+}
diff --git a/kibana/files/objects/visualization_NOTIFICATIONS-PER-SEVERITY.json b/kibana/files/objects/visualization_NOTIFICATIONS-PER-SEVERITY.json
new file mode 100644
index 0000000..4a7c361
--- /dev/null
+++ b/kibana/files/objects/visualization_NOTIFICATIONS-PER-SEVERITY.json
@@ -0,0 +1,10 @@
+{
+  "title": "NOTIFICATIONS PER SEVERITY",
+  "visState": "{\n  \"title\": \"New Visualization\",\n  \"type\": \"histogram\",\n  \"params\": {\n    \"shareYAxis\": true,\n    \"addTooltip\": true,\n    \"addLegend\": true,\n    \"scale\": \"linear\",\n    \"mode\": \"stacked\",\n    \"times\": [],\n    \"addTimeMarker\": false,\n    \"defaultYExtents\": false,\n    \"setYExtents\": false,\n    \"yAxis\": {}\n  },\n  \"aggs\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"count\",\n      \"schema\": \"metric\",\n      \"params\": {}\n    },\n    {\n      \"id\": \"2\",\n      \"type\": \"terms\",\n      \"schema\": \"segment\",\n      \"params\": {\n        \"field\": \"severity_label\",\n        \"size\": 10,\n        \"order\": \"desc\",\n        \"orderBy\": \"1\"\n      }\n    }\n  ],\n  \"listeners\": {}\n}",
+  "uiStateJSON": "{\n  \"vis\": {\n    \"colors\": {\n      \"ERROR\": \"#BF1B00\",\n      \"EMERGENCY\": \"#99440A\",\n      \"WARNING\": \"#EF843C\",\n      \"INFO\": \"#7EB26C\",\n      \"DEBUG\": \"#1F78C1\",\n      \"NOTICE\": \"#6ED0E0\",\n      \"ALERT\": \"#1F78C1\"\n    }\n  }\n}",
+  "description": "",
+  "version": 1,
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\n  \"index\": \"notification-*\",\n  \"query\": {\n    \"query_string\": {\n      \"query\": \"*\",\n      \"analyze_wildcard\": true\n    }\n  },\n  \"filter\": []\n}"
+  }
+}
diff --git a/kibana/files/objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-ROLE.json b/kibana/files/objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-ROLE.json
new file mode 100644
index 0000000..4c6bbe8
--- /dev/null
+++ b/kibana/files/objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-ROLE.json
@@ -0,0 +1,10 @@
+{
+  "title": "NUMBER OF LOG MESSAGES PER ROLE",
+  "visState": "{\"title\":\"Number of log messages per role\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{\"customLabel\":\"\"}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"openstack_roles\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"Roles\"}}],\"listeners\":{}}",
+  "uiStateJSON": "{\"vis\":{\"colors\":{\"Count\":\"#CCA300\"}},\"spy\":{\"mode\":{\"name\":\"table\",\"fill\":false}}}",
+  "description": "",
+  "version": 1,
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\"index\":\"log-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}"
+  }
+}
diff --git a/kibana/files/objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-SEVERITY.json b/kibana/files/objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-SEVERITY.json
new file mode 100644
index 0000000..e447b7e
--- /dev/null
+++ b/kibana/files/objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-SEVERITY.json
@@ -0,0 +1,10 @@
+{
+  "title": "NUMBER OF LOG MESSAGES PER SEVERITY",
+  "visState": "{\"title\":\"NUMBER OF LOG MESSAGES PER SEVERITY\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{\"customLabel\":\"\"}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"severity_label\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"Number of log messages per severity\"}}],\"listeners\":{}}",
+  "uiStateJSON": "{\"vis\":{\"colors\":{\"Count\":\"#CCA300\"}}}",
+  "description": "",
+  "version": 1,
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\"index\":\"log-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}"
+  }
+}
diff --git a/kibana/files/objects/visualization_SOURCE-BREAKDOWN.json b/kibana/files/objects/visualization_SOURCE-BREAKDOWN.json
new file mode 100644
index 0000000..d1d75ae
--- /dev/null
+++ b/kibana/files/objects/visualization_SOURCE-BREAKDOWN.json
@@ -0,0 +1,10 @@
+{
+  "title": "SOURCE BREAKDOWN",
+  "visState": "{\"title\":\"New Visualization\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"scale\":\"linear\",\"mode\":\"grouped\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"Logger\",\"size\":15,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+  "uiStateJSON": "{}",
+  "description": "",
+  "version": 1,
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\"index\":\"notification-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}"
+  }
+}
diff --git a/kibana/files/objects/visualization_TOP-10-HOSTS.json b/kibana/files/objects/visualization_TOP-10-HOSTS.json
new file mode 100644
index 0000000..797a8b4
--- /dev/null
+++ b/kibana/files/objects/visualization_TOP-10-HOSTS.json
@@ -0,0 +1,10 @@
+{
+  "title": "TOP 10 HOSTS",
+  "visState": "{\n  \"title\": \"TOP 10 HOSTS\",\n  \"type\": \"histogram\",\n  \"params\": {\n    \"shareYAxis\": true,\n    \"addTooltip\": true,\n    \"addLegend\": true,\n    \"scale\": \"linear\",\n    \"mode\": \"stacked\",\n    \"times\": [],\n    \"addTimeMarker\": false,\n    \"defaultYExtents\": false,\n    \"setYExtents\": false,\n    \"yAxis\": {}\n  },\n  \"aggs\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"count\",\n      \"schema\": \"metric\",\n      \"params\": {}\n    },\n    {\n      \"id\": \"2\",\n      \"type\": \"terms\",\n      \"schema\": \"segment\",\n      \"params\": {\n        \"field\": \"Hostname\",\n        \"size\": 10,\n        \"order\": \"desc\",\n        \"orderBy\": \"1\",\n        \"customLabel\": \"Nodes\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"type\": \"terms\",\n      \"schema\": \"group\",\n      \"params\": {\n        \"field\": \"severity_label\",\n        \"size\": 8,\n        \"order\": \"desc\",\n        \"orderBy\": \"1\"\n      }\n    }\n  ],\n  \"listeners\": {}\n}",
+  "uiStateJSON": "{\n  \"vis\": {\n    \"colors\": {\n      \"ERROR\": \"#BF1B00\",\n      \"EMERGENCY\": \"#99440A\",\n      \"WARNING\": \"#EF843C\",\n      \"INFO\": \"#7EB26C\",\n      \"DEBUG\": \"#1F78C1\",\n      \"NOTICE\": \"#6ED0E0\",\n      \"ALERT\": \"#1F78C1\"\n    }\n  }\n}",
+  "description": "",
+  "version": 1,
+  "kibanaSavedObjectMeta": {
+    "searchSourceJSON": "{\n  \"index\": \"log-*\",\n  \"query\": {\n    \"query_string\": {\n      \"analyze_wildcard\": true,\n      \"query\": \"*\"\n    }\n  },\n  \"filter\": []\n}"
+  }
+}
diff --git a/kibana/files/objects/visualization_TOP-10-PROGRAMS.json b/kibana/files/objects/visualization_TOP-10-PROGRAMS.json
new file mode 100644
index 0000000..f65457d
--- /dev/null
+++ b/kibana/files/objects/visualization_TOP-10-PROGRAMS.json
@@ -0,0 +1,10 @@
+{
+ "title": "TOP 10 PROGRAMS",
+ "visState": "{\n  \"title\": \"TOP 10 PROGRAMS\",\n  \"type\": \"histogram\",\n  \"params\": {\n    \"shareYAxis\": true,\n    \"addTooltip\": true,\n    \"addLegend\": true,\n    \"scale\": \"linear\",\n    \"mode\": \"stacked\",\n    \"times\": [],\n    \"addTimeMarker\": false,\n    \"defaultYExtents\": false,\n    \"setYExtents\": false,\n    \"yAxis\": {}\n  },\n  \"aggs\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"count\",\n      \"schema\": \"metric\",\n      \"params\": {\n        \"customLabel\": \"\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"type\": \"terms\",\n      \"schema\": \"segment\",\n      \"params\": {\n        \"field\": \"programname\",\n        \"size\": 10,\n        \"order\": \"desc\",\n        \"orderBy\": \"1\",\n        \"customLabel\": \"Number of log messages per programname\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"type\": \"terms\",\n      \"schema\": \"group\",\n      \"params\": {\n        \"field\": \"severity_label\",\n        \"size\": 8,\n        \"order\": \"desc\",\n        \"orderBy\": \"1\"\n      }\n    }\n  ],\n  \"listeners\": {}\n}",
+ "uiStateJSON": "{\n  \"vis\": {\n    \"colors\": {\n      \"ERROR\": \"#BF1B00\",\n      \"EMERGENCY\": \"#99440A\",\n      \"WARNING\": \"#EF843C\",\n      \"INFO\": \"#7EB26C\",\n      \"DEBUG\": \"#1F78C1\",\n      \"NOTICE\": \"#6ED0E0\",\n      \"ALERT\": \"#1F78C1\"\n    }\n  }\n}",
+ "description": "",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+   "searchSourceJSON": "{\n  \"index\": \"log-*\",\n  \"query\": {\n    \"query_string\": {\n      \"analyze_wildcard\": true,\n      \"query\": \"*\"\n    }\n  },\n  \"filter\": []\n}"
+ }
+}
diff --git a/kibana/files/objects/visualization_TOP-10-SOURCES.json b/kibana/files/objects/visualization_TOP-10-SOURCES.json
new file mode 100644
index 0000000..966056a
--- /dev/null
+++ b/kibana/files/objects/visualization_TOP-10-SOURCES.json
@@ -0,0 +1,10 @@
+{
+ "title": "TOP 10 SOURCES",
+ "visState": "{\"title\":\"TOP 10 SOURCES\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{\"customLabel\":\"\"}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"Logger\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"Number of log messages per Logger\"}},{\"id\":\"3\",\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"severity_label\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "uiStateJSON": "{\n  \"vis\": {\n    \"colors\": {\n      \"ERROR\": \"#BF1B00\",\n      \"EMERGENCY\": \"#99440A\",\n      \"WARNING\": \"#EF843C\",\n      \"INFO\": \"#7EB26C\",\n      \"DEBUG\": \"#1F78C1\",\n      \"NOTICE\": \"#6ED0E0\",\n      \"ALERT\": \"#1F78C1\"\n    }\n  }\n}",
+ "description": "",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+   "searchSourceJSON": "{\"index\":\"log-*\",\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}},\"filter\":[]}"
+ }
+}
diff --git a/kibana/init.sls b/kibana/init.sls
index 2003aa5..627e913 100644
--- a/kibana/init.sls
+++ b/kibana/init.sls
@@ -1,5 +1,10 @@
 
-{%- if pillar.kibana.server is defined %}
+{%- if pillar.kibana is defined %}
 include:
+{%- if pillar.kibana.server is defined %}
 - kibana.server
 {%- endif %}
+{%- if pillar.kibana.client is defined %}
+- kibana.client
+{%- endif %}
+{%- endif %}
diff --git a/kibana/map.jinja b/kibana/map.jinja
index cedacb3..0a6540a 100644
--- a/kibana/map.jinja
+++ b/kibana/map.jinja
@@ -6,3 +6,12 @@
         'configpath': '/opt/kibana/config/kibana.yml',
     },
 }, merge=salt['pillar.get']('kibana:server')) %}
+
+{%- load_yaml as client_defaults %}
+default:
+  server:
+    host: 127.0.0.1
+    port: 9200
+    index: '.kibana'
+{%- endload %}
+{%- set client = salt['grains.filter_by'](client_defaults, merge=salt['pillar.get']('kibana:client')) %}
diff --git a/kibana/meta/collectd.yml b/kibana/meta/collectd.yml
new file mode 100644
index 0000000..b94e8e1
--- /dev/null
+++ b/kibana/meta/collectd.yml
@@ -0,0 +1,11 @@
+{%- if pillar.kibana.server is defined %}
+{%- from "kibana/map.jinja" import server with context %}
+
+{%- if server.get('enabled', False) %}
+local_plugin:
+  collectd_processes:
+    process:
+      kibana:
+        match: 'node.*kibana'
+{%- endif %}
+{%- endif %}
diff --git a/metadata/service/client.yml b/metadata/service/client.yml
new file mode 100644
index 0000000..c2915d8
--- /dev/null
+++ b/metadata/service/client.yml
@@ -0,0 +1,85 @@
+applications:
+- kibana.client
+parameters:
+  kibana:
+    client:
+      enabled: true
+      object:
+        '4.5.1':
+          enabled: true
+          template: kibana/files/objects/config.json
+          type: 'config'
+        logs:
+          enabled: true
+          template: kibana/files/objects/dashboard_logs.json
+          type: dashboard
+        notifications:
+          enabled: true
+          template: kibana/files/objects/dashboard_notifications.json
+          type: dashboard
+        'log-*':
+          template: kibana/files/objects/index-pattern_logs.json
+          type: index-pattern
+        'notification-*':
+          template: kibana/files/objects/index-pattern_notifications.json
+          type: index-pattern
+        search-logs:
+          enabled: true
+          template: kibana/files/objects/search_logs.json
+          type: search
+        search-notifications:
+          enabled: true
+          template: kibana/files/objects/search_notifications.json
+          type: search
+        LOG-MESSAGES-OVER-TIME-PER-SEVERITY:
+          enabled: true
+          template: kibana/files/objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SEVERITY.json
+          type: visualization
+        LOG-MESSAGES-OVER-TIME-PER-SOURCE:
+          enabled: true
+          template: kibana/files/objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SOURCE.json
+          type: visualization
+        NUMBER-OF-LOG-MESSAGES-PER-ROLE:
+          enabled: true
+          template: kibana/files/objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-ROLE.json
+          type: visualization
+        NUMBER-OF-LOG-MESSAGES-PER-SEVERITY:
+          enabled: true
+          template: kibana/files/objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-SEVERITY.json
+          type: visualization
+        TOP-10-HOSTS:
+          enabled: true
+          template: kibana/files/objects/visualization_TOP-10-HOSTS.json
+          type: visualization
+        TOP-10-PROGRAMS:
+          enabled: true
+          template: kibana/files/objects/visualization_TOP-10-PROGRAMS.json
+          type: visualization
+        TOP-10-SOURCES:
+          enabled: true
+          template: kibana/files/objects/visualization_TOP-10-SOURCES.json
+          type: visualization
+        NOTIFICATIONS-OVER-TIME-PER-SOURCE:
+          enabled: true
+          template: kibana/files/objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SOURCE.json
+          type: visualization
+        NOTIFICATIONS-OVER-TIME-PER-SEVERITY:
+          enabled: true
+          template: kibana/files/objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SEVERITY.json
+          type: visualization
+        EVENT-TYPE-BREAKDOWN:
+          enabled: true
+          template: kibana/files/objects/visualization_EVENT-TYPE-BREAKDOWN.json
+          type: visualization
+        SOURCE-BREAKDOWN:
+          enabled: true
+          template: kibana/files/objects/visualization_SOURCE-BREAKDOWN.json
+          type: visualization
+        HOST-BREAKDOWN:
+          enabled: true
+          template: kibana/files/objects/visualization_HOST-BREAKDOWN.json
+          type: visualization
+        NOTIFICATIONS-PER-SEVERITY:
+          enabled: true
+          template: kibana/files/objects/visualization_NOTIFICATIONS-PER-SEVERITY.json
+          type: visualization
diff --git a/metadata/service/server/single.yml b/metadata/service/server/single.yml
index fd6d447..3ca67fc 100644
--- a/metadata/service/server/single.yml
+++ b/metadata/service/server/single.yml
@@ -1,5 +1,7 @@
 applications:
 - kibana
+classes:
+- service.kibana.support
 parameters:
   kibana:
     server:
diff --git a/metadata/service/support.yml b/metadata/service/support.yml
index 86aa163..b1735ad 100644
--- a/metadata/service/support.yml
+++ b/metadata/service/support.yml
@@ -2,7 +2,7 @@
   kibana:
     _support:
       collectd:
-        enabled: false
+        enabled: true
       heka:
         enabled: false
       sensu: