diff --git a/deployment_scripts/puppet/manifests/firewall.pp b/deployment_scripts/puppet/manifests/firewall.pp index 105a511..53832a0 100644 --- a/deployment_scripts/puppet/manifests/firewall.pp +++ b/deployment_scripts/puppet/manifests/firewall.pp @@ -62,6 +62,12 @@ firewall { '110 elasticsearch clustering': action => 'accept', } +firewall { '101 haproxy kibana': + port => hiera('lma::elasticsearch::kibana_frontend_port'), + proto => 'tcp', + action => 'accept', +} + firewall { '101 kibana': port => hiera('lma::elasticsearch::kibana_port'), proto => 'tcp', diff --git a/deployment_scripts/puppet/manifests/haproxy.pp b/deployment_scripts/puppet/manifests/haproxy.pp index 85e0309..f671883 100644 --- a/deployment_scripts/puppet/manifests/haproxy.pp +++ b/deployment_scripts/puppet/manifests/haproxy.pp @@ -15,7 +15,8 @@ notice('fuel-plugin-elasticsearch-kibana: haproxy.pp') $es_port = hiera('lma::elasticsearch::rest_port') -$nginx_port = hiera('lma::elasticsearch::kibana_port') +$kibana_backend_port = hiera('lma::elasticsearch::kibana_port') +$kibana_frontend_port = hiera('lma::elasticsearch::kibana_frontend_port') $vip = hiera('lma::elasticsearch::vip') $nodes_ips = hiera('lma::elasticsearch::nodes') @@ -30,7 +31,8 @@ Openstack::Ha::Haproxy_service { internal_virtual_ip => $vip, } -openstack::ha::haproxy_service { 'elasticsearch-rest': +$es_haproxy_service = hiera('lma::elasticsearch::es_haproxy_service') +openstack::ha::haproxy_service { $es_haproxy_service: order => '920', listen_port => $es_port, balancermember_port => $es_port, @@ -44,8 +46,8 @@ openstack::ha::haproxy_service { 'elasticsearch-rest': openstack::ha::haproxy_service { 'kibana': order => '921', - listen_port => $nginx_port, - balancermember_port => $nginx_port, + listen_port => $kibana_frontend_port, + balancermember_port => $kibana_backend_port, balancermember_options => 'check inter 10s fastinter 2s downinter 3s rise 3 fall 3', haproxy_config_options => { 'option' => ['httplog', 'http-keep-alive', 'prefer-last-server', 'dontlog-normal'], diff --git a/deployment_scripts/puppet/manifests/hiera_override.pp b/deployment_scripts/puppet/manifests/hiera_override.pp index 9941368..dba2fa6 100644 --- a/deployment_scripts/puppet/manifests/hiera_override.pp +++ b/deployment_scripts/puppet/manifests/hiera_override.pp @@ -66,9 +66,12 @@ $calculated_content = inline_template(' lma::corosync_roles: - primary-elasticsearch_kibana - elasticsearch_kibana -lma::elasticsearch::vip: <%= @vip%> +lma::elasticsearch::vip: <%= @vip %> +lma::elasticsearch::es_haproxy_service: elasticsearch-rest lma::elasticsearch::listen_address: <%= @listen_address%> -lma::elasticsearch::kibana_port: 80 +lma::elasticsearch::kibana_frontend_port: 80 +lma::elasticsearch::kibana_port: 5601 +lma::elasticsearch::kibana_index: .kibana lma::elasticsearch::rest_port: 9200 lma::elasticsearch::clustering_port: 9300 lma::elasticsearch::nodes: @@ -77,7 +80,7 @@ lma::elasticsearch::nodes: <% end -%> lma::elasticsearch::number_of_replicas: <%= @number_of_replicas %> lma::elasticsearch::minimum_master_nodes: <%= @minimum_master_nodes %> -lma::elasticsearch::recover_after_time: <%= @recover_after_time %> +lma::elasticsearch::recover_after_time: <%= @recover_after_time %>m lma::elasticsearch::recover_after_nodes: <%= @recover_after_nodes %> lma::elasticsearch::data_dir: "<%= @elasticsearch_kibana["data_dir"] %>" lma::elasticsearch::jvm_size: <%= @elasticsearch_kibana["jvm_heap_size"] %> diff --git a/deployment_scripts/puppet/manifests/kibana.pp b/deployment_scripts/puppet/manifests/kibana.pp index bc0b695..2fbf7c2 100644 --- a/deployment_scripts/puppet/manifests/kibana.pp +++ b/deployment_scripts/puppet/manifests/kibana.pp @@ -19,4 +19,5 @@ class { 'lma_logging_analytics::kibana': listen_port => hiera('lma::elasticsearch::kibana_port'), es_host => hiera('lma::elasticsearch::vip'), es_port => hiera('lma::elasticsearch::rest_port'), + version => '4.5.1', } diff --git a/deployment_scripts/puppet/manifests/kibana_index_configuration.pp b/deployment_scripts/puppet/manifests/kibana_index_configuration.pp new file mode 100644 index 0000000..57f0f95 --- /dev/null +++ b/deployment_scripts/puppet/manifests/kibana_index_configuration.pp @@ -0,0 +1,49 @@ +# Copyright 2016 Mirantis, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +notice('fuel-plugin-elasticsearch-kibana: kibana_index_configuration.pp') + +$vip = hiera('lma::elasticsearch::vip') +$es_port = hiera('lma::elasticsearch::rest_port') +$kibana_index = hiera('lma::elasticsearch::kibana_index') + +# Elasticsearch must be reachable through HAproxy before the template creation. +# This is due the fact that The Elasticsearch Puppet module miserably fails +# when HAproxy responds 503 with HTML content and this leads to never create +# the template. +haproxy_backend_status { 'elasticsearch': + name => hiera('lma::elasticsearch::es_haproxy_service'), + socket => '/var/lib/haproxy/stats', +} + +# Kibana4 creates automatically its index when starting and configures fields +# mapping on the fly when first objects are created through the UI. +# In order to automate the dashboards importation, the Elasticsearch index +# template for Kibana4 must be created before Kibana starts. +# Then, correct fields mapping are present before importing objects +# (searches, visualizations and dashboards). +lma_logging_analytics::es_template { 'kibana4': + host => $vip, + port => $es_port, + index_template => $kibana_index, + require => Haproxy_backend_status['elasticsearch'], +} + +# Import all Kibana objects in one time by issuing a Bulk request +class { 'lma_logging_analytics::kibana_dashboards': + host => $vip, + port => $es_port, + index => $kibana_index, + require => Lma_logging_analytics::Es_template['kibana4'], +} diff --git a/deployment_scripts/puppet/manifests/provision_services.pp b/deployment_scripts/puppet/manifests/provision_services.pp index d38a4a1..39056d7 100644 --- a/deployment_scripts/puppet/manifests/provision_services.pp +++ b/deployment_scripts/puppet/manifests/provision_services.pp @@ -17,25 +17,21 @@ notice('fuel-plugin-elasticsearch-kibana: provision_services.pp') $deployment_id = hiera('deployment_id') $master_ip = hiera('master_ip') $vip = hiera('lma::elasticsearch::vip') -$kibana_port = hiera('lma::elasticsearch::kibana_port') +$kibana_port = hiera('lma::elasticsearch::kibana_frontend_port') $es_port = hiera('lma::elasticsearch::rest_port') $number_of_replicas = hiera('lma::elasticsearch::number_of_replicas') $kibana_link_data = "{\"title\":\"Kibana\",\ \"description\":\"Dashboard for visualizing logs and notifications\",\ -\"url\":\"http://${vip}:${port}/\"}" +\"url\":\"http://${vip}:${kibana_port}/\"}" $kibana_link_created_file = '/var/cache/kibana_link_created' $elasticsearch_kibana = hiera_hash('elasticsearch_kibana') -lma_logging_analytics::es_template { ['log', 'notification', 'kibana']: +lma_logging_analytics::es_template { ['log', 'notification']: number_of_replicas => $number_of_replicas, host => $vip, port => $es_port, } -> -lma_logging_analytics::kibana_dashboard { ['logs', 'notifications']: - host => $vip, - port => $es_port, -} -> class { 'lma_logging_analytics::curator': host => $vip, port => $es_port, diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/.fixtures.yml b/deployment_scripts/puppet/modules/lma_logging_analytics/.fixtures.yml index a1763f3..ea4f5d3 100644 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/.fixtures.yml +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/.fixtures.yml @@ -6,9 +6,6 @@ fixtures: elasticsearch: repo: "git://github.com/elastic/puppet-elasticsearch" ref: "0.9.1" - nginx: - repo: "git://github.com/jfryman/puppet-nginx" - ref: "v0.2.2" concat: repo: "git://github.com/puppetlabs/puppetlabs-concat" ref: "1.2.4" diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/lib/puppet/parser/functions/encode_kibana_dashboard.rb b/deployment_scripts/puppet/modules/lma_logging_analytics/lib/puppet/parser/functions/encode_kibana_dashboard.rb deleted file mode 100644 index 130a730..0000000 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/lib/puppet/parser/functions/encode_kibana_dashboard.rb +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# Encode a Kibana dashboard file -require 'json' - -module Puppet::Parser::Functions - newfunction(:encode_kibana_dashboard, :type => :rvalue, :doc => <<-EOS - Encodes a Kibana dashboard for storing it to Elasticsearch. - EOS - ) do |args| - raise(Puppet::ParseError, "encode_kibana_dashboard(): Wrong number of " + - "arguments given (#{args.size} for 4)") if args.size != 4 - - user = args[0] - group = args[1] - title = args[2] - data = args[3] - - return JSON.generate({ - 'user' => user, - 'group' => group, - 'title' => title, - 'dashboard' => data - }) - end -end diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/lib/puppet/provider/elasticsearch.rb b/deployment_scripts/puppet/modules/lma_logging_analytics/lib/puppet/provider/elasticsearch.rb new file mode 100644 index 0000000..e2c188a --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/lib/puppet/provider/elasticsearch.rb @@ -0,0 +1,89 @@ +# Copyright 2016 Mirantis, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +require 'json' +require 'net/http' + +class Puppet::Provider::Elasticsearch < Puppet::Provider + # Helper methods + def elasticsearch_host + unless @elasticsearch_host + @elasticsearch_host = URI.parse(resource[:url]).host + end + @elasticsearch_host + end + + def elasticsearch_port + unless @elasticsearch_port + @elasticsearch_port = URI.parse(resource[:url]).port + end + @elasticsearch_port + end + + def elasticsearch_scheme + unless @elasticsearch_scheme + @elasticsearch_scheme = URI.parse(resource[:url]).scheme + end + @elasticsearch_scheme + end + + # Return a Net::HTTP::Response object + def send_request(operation="GET", path="", data=nil, search_path={}) + request = nil + encoded_search = "" + + if URI.respond_to?(:encode_www_form) + encoded_search = URI.encode_www_form(search_path) + else + # Ideally we would have use URI.encode_www_form but it isn't + # available with Ruby 1.8.x that ships with CentOS 6.5. + encoded_search = search_path.to_a.map do |x| + x.map{|y| CGI.escape(y.to_s)}.join('=') + end + encoded_search = encoded_search.join('&') + end + + url = "%s://%s:%d%s?%s" % [ + self.elasticsearch_scheme, self.elasticsearch_host, self.elasticsearch_port, + path, encoded_search] + + Puppet.debug "URL #{operation} #{url}" + + uri = URI.parse(url) + + case operation.upcase + when 'POST' + request = Net::HTTP::Post.new(uri.request_uri) + request.body = data.to_json() + when 'PUT' + request = Net::HTTP::Put.new(uri.request_uri) + request.body = data.to_json() + when 'GET' + request = Net::HTTP::Get.new(uri.request_uri) + when 'DELETE' + request = Net::HTTP::Delete.new(uri.request_uri) + when 'HEAD' + request = Net::HTTP::Head.new(uri.request_uri) + else + raise Puppet::Error, "Unsupported HTTP operation '%s'" % operation + end + + request.content_type = 'application/json' + return Net::HTTP.start(self.elasticsearch_host, self.elasticsearch_port) do |http| + http.request(request) + end + end +end + + diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/lib/puppet/provider/kibana_object/elasticsearch.rb b/deployment_scripts/puppet/modules/lma_logging_analytics/lib/puppet/provider/kibana_object/elasticsearch.rb new file mode 100644 index 0000000..d39ae04 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/lib/puppet/provider/kibana_object/elasticsearch.rb @@ -0,0 +1,83 @@ +# Copyright 2016 Mirantis, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +require 'json' + +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'elasticsearch')) + +Puppet::Type.type(:kibana_object).provide(:elasticsearch, :parent => Puppet::Provider::Elasticsearch) do + desc "Support for Kibana objects stored into Elasticsearch" + + defaultfor :kernel => 'Linux' + + def get_object_url + url = "/%s/%s/%s" % [resource[:elasticsearch_index], resource[:type], resource[:id]] + end + + # Return the object matching with the resource's title + def find_object + url = get_object_url() + + response = self.send_request('HEAD', url) + + case response.code + when '404' + return + when '200' + response = self.send_request('GET', url) + @obj = JSON.parse(response.body)['_source'] + else + fail("Fail to retrieve object '%s' (HTTP response: %s/%s)" % + [url, response.code, response.body]) + end + end + + def content + @obj + end + + def check_response(operation, http_response) + Puppet.debug http_response.body + success = JSON.parse(http_response.body)['_shards']['successful'] + if success == 0 + url = get_object_url() + fail("Fail to #{operation} object #{url} (HTTP response #{response.body})") + end + end + + def save_object(obj) + url = get_object_url() + response = self.send_request('PUT', url, obj) + check_response('save', response) + end + + def content=(value) + self.save_object(value) + end + + def create + self.save_object(resource[:content]) + end + + def destroy + url = get_object_url() + response = self.send_request('DELETE', url) + + check_response('delete', response) + end + + def exists? + self.find_object() + end +end diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/lib/puppet/type/kibana_object.rb b/deployment_scripts/puppet/modules/lma_logging_analytics/lib/puppet/type/kibana_object.rb new file mode 100644 index 0000000..b91420f --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/lib/puppet/type/kibana_object.rb @@ -0,0 +1,81 @@ +# Copyright 2016 Mirantis, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +require 'json' + +Puppet::Type.newtype(:kibana_object) do + @doc = "Manage Kibana objects" + + ensurable + + newparam(:id, :namevar => true) do + desc "The id of the object." + end + + newparam(:type) do + desc "The type of the object. + valid type is one of: search, visualization, index-pattern or config + " + newvalues(:dashboard, :visualization, :search, :config, "index-pattern") + end + + newproperty(:content) do + desc "The JSON representation of the object." + + validate do |value| + begin + JSON.parse(value) + rescue JSON::ParserError + raise ArgumentError , "Invalid JSON string for content" + end + end + + munge do |value| + JSON.parse(value) + end + + def should_to_s(value) + if value.length > 12 + "#{value.to_s.slice(0,12)}..." + else + value + end + end + + def is_to_s(value) + should_to_s(value) + end + end + + newparam(:url) do + desc "The URL of the Elasticseach server" + defaultto "" + + validate do |value| + unless value =~ /^https?:\/\// + raise ArgumentError , "'%s' is not a valid URL" % value + end + end + end + + newparam(:elasticsearch_index) do + defaultto ".kibana" + + desc "The Elasticseach index server (optional)" + end + + validate do + fail('content is required when ensure is present') if self[:ensure] == :present and self[:content].nil? + end +end diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/es_template.pp b/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/es_template.pp index 019e07f..d16d85d 100644 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/es_template.pp +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/es_template.pp @@ -19,8 +19,13 @@ define lma_logging_analytics::es_template ( $number_of_replicas = 0, $host = 'localhost', $port = 9200, + $index_template = undef, ) { - $index_prefix = $title + if $index_template { + $template = $index_template + } else { + $template = "${title}-*" + } elasticsearch::template { $title: content => template("lma_logging_analytics/es_template_${title}.json.erb"), diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/kibana.pp b/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/kibana.pp index 8e2f415..8b80f2b 100644 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/kibana.pp +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/kibana.pp @@ -20,6 +20,8 @@ class lma_logging_analytics::kibana ( $listen_port, $es_host = 'localhost', $es_port = 9200, + $es_scheme = 'http', + $version = 'latest' ) { include lma_logging_analytics::params @@ -28,32 +30,22 @@ class lma_logging_analytics::kibana ( $kibana_conf = $lma_logging_analytics::params::kibana_config $default_route = $lma_logging_analytics::params::kibana_default_route - # Deploy Kibana - file { $kibana_dir: - source => 'puppet:///modules/lma_logging_analytics/kibana/src', - recurse => true, + package { 'kibana': + ensure => $version, } - # Replace config.js - file { $kibana_conf: - ensure => file, - content => template('lma_logging_analytics/config.js.erb'), - require => File[$kibana_dir], + file { '/opt/kibana/config/kibana.yml': + ensure => present, + content => template('lma_logging_analytics/kibana4.yaml.erb'), + notify => Service['kibana'], + require => Package['kibana'], } - # Install nginx - class { 'nginx': - manage_repo => false, - nginx_vhosts => { - 'kibana.local' => { - 'www_root' => $kibana_dir - } - }, - nginx_vhosts_defaults => { - 'listen_ip' => $listen_address, - 'listen_port' => $listen_port, - 'listen_options' => 'default_server' - }, - require => File[$kibana_conf], + service { 'kibana': + ensure => 'running', + enable => true, + hasstatus => true, + hasrestart => true, + require => Package['kibana'], } } diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/kibana_dashboard.pp b/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/kibana_dashboard.pp deleted file mode 100644 index 2c35922..0000000 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/kibana_dashboard.pp +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -define lma_logging_analytics::kibana_dashboard ( - $host = 'localhost', - $port = '9200', -) { - include lma_logging_analytics::params - - $es_url = "http://${host}:${port}" - $dashboard_title = join([$lma_logging_analytics::params::kibana_dashboard_prefix, capitalize($title)], '') - $dashboard_id = uriescape($dashboard_title) - - # Note that the dashboards are stored in templates/ because it is the only way - # for us to read the content of the file. Ideally we would have used the - # file() function but until Puppet 3.7 it only works with absolute paths. - # See http://www.unixdaemon.net/tools/puppet/puppet-3.7-file-function.html - # for details - $content = template("lma_logging_analytics/kibana_dashboards/${title}.json") - - $dashboard_source = encode_kibana_dashboard('guest', 'guest', $dashboard_title, $content) - - exec { $title: - onlyif => "/usr/bin/curl -sL -w \"%{http_code}\\n\" -XHEAD ${es_url}/kibana-int/dashboard/${dashboard_id} | grep 404 > /dev/null", - command => "/usr/bin/curl -sL -w \"%{http_code}\\n\" -XPUT ${es_url}/kibana-int/dashboard/${dashboard_id} -d '${dashboard_source}' -o /dev/null | egrep \"(200|201)\" > /dev/null", - } -} diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/kibana_dashboards.pp b/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/kibana_dashboards.pp new file mode 100644 index 0000000..fc203d9 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/manifests/kibana_dashboards.pp @@ -0,0 +1,119 @@ +# Copyright 2015 Mirantis, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +class lma_logging_analytics::kibana_dashboards ( + $host = 'localhost', + $port = '9200', + $index = '.kibana', +) { + include lma_logging_analytics::params + + # Note that the dashboards are stored in templates/ because it is the only way + # for us to read the content of the file. Ideally we would have used the + # file() function but until Puppet 3.7 it only works with absolute paths. + # See http://www.unixdaemon.net/tools/puppet/puppet-3.7-file-function.html + # for details + + $default = { + url => "http://${host}:${port}", + elasticsearch_index => $index, + } + + $objects = { + '4.5.1' => { + content => template('lma_logging_analytics/kibana4_objects/config.json'), + type => 'config', + }, + 'log-*' => { + content => template('lma_logging_analytics/kibana4_objects/index-pattern_logs.json'), + type => 'index-pattern', + }, + 'Logs' => { + content => template('lma_logging_analytics/kibana4_objects/dashboard_logs.json'), + type => 'dashboard', + }, + 'search-logs' => { + content => template('lma_logging_analytics/kibana4_objects/search_logs.json'), + type => 'search', + }, + 'LOG-MESSAGES-OVER-TIME-PER-SEVERITY' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SEVERITY.json'), + type => 'visualization', + }, + 'LOG-MESSAGES-OVER-TIME-PER-SOURCE' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SOURCE.json'), + type => 'visualization', + }, + 'NUMBER-OF-LOG-MESSAGES-PER-ROLE' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-ROLE.json'), + type => 'visualization', + }, + 'NUMBER-OF-LOG-MESSAGES-PER-SEVERITY' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-SEVERITY.json'), + type => 'visualization', + }, + 'TOP-10-HOSTS' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_TOP-10-HOSTS.json'), + type => 'visualization', + }, + 'TOP-10-PROGRAMS' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_TOP-10-PROGRAMS.json'), + type => 'visualization', + }, + 'TOP-10-SOURCES' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_TOP-10-SOURCES.json'), + type => 'visualization', + }, + 'notification-*' => { + content => template('lma_logging_analytics/kibana4_objects/index-pattern_notifications.json'), + type => 'index-pattern', + }, + 'Notifications' => { + content => template('lma_logging_analytics/kibana4_objects/dashboard_notifications.json'), + type => 'dashboard', + }, + 'NOTIFICATIONS-OVER-TIME-PER-SOURCE' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SOURCE.json'), + type => 'visualization', + }, + 'NOTIFICATIONS-OVER-TIME-PER-SEVERITY' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SEVERITY.json'), + type => 'visualization', + }, + 'EVENT-TYPE-BREAKDOWN' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_EVENT-TYPE-BREAKDOWN.json'), + type => 'visualization', + }, + 'SOURCE-BREAKDOWN' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_SOURCE-BREAKDOWN.json'), + type => 'visualization', + }, + 'HOST-BREAKDOWN' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_HOST-BREAKDOWN.json'), + type => 'visualization', + }, + 'NOTIFICATIONS-PER-SEVERITY' => { + content => template('lma_logging_analytics/kibana4_objects/visualization_NOTIFICATIONS-PER-SEVERITY.json'), + type => 'visualization', + }, + 'search-notifications' => { + content => template('lma_logging_analytics/kibana4_objects/search_notifications.json'), + type => 'search', + }, + } + + create_resources( + kibana_object, $objects, $default + ) +} diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/spec/classes/lma_logging_analytics_kibana_spec.rb b/deployment_scripts/puppet/modules/lma_logging_analytics/spec/classes/lma_logging_analytics_kibana_spec.rb index e5da817..775a777 100644 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/spec/classes/lma_logging_analytics_kibana_spec.rb +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/spec/classes/lma_logging_analytics_kibana_spec.rb @@ -20,10 +20,12 @@ describe 'lma_logging_analytics::kibana' do end let(:params) do - {:listen_address => '127.0.0.1', :listen_port => 80} + {:listen_address => '127.0.0.1', :listen_port => 80, + :version => '42.24'} end - it { should create_file('/opt/kibana')} - it { should create_file('/opt/kibana/config.js')} - it { should create_class('nginx')} + it { should contain_package('kibana').with( + :ensure => '42.24') + } + it { should contain_service('kibana')} end diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/spec/defines/lma_logging_analytics_kibana_dashboard_spec.rb b/deployment_scripts/puppet/modules/lma_logging_analytics/spec/defines/lma_logging_analytics_kibana_dashboard_spec.rb deleted file mode 100644 index 5d7510e..0000000 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/spec/defines/lma_logging_analytics_kibana_dashboard_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -require 'spec_helper' - -describe 'lma_logging_analytics::kibana_dashboard' do - let(:title) { 'logs' } - let(:facts) do - {:kernel => 'Linux', :operatingsystem => 'Ubuntu', - :concat_basedir => '/foo'} - end - - describe 'with defaults' do - it { is_expected.to contain_exec('logs') } - end -end diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/spec/fixtures/modules/lma_logging_analytics/lib b/deployment_scripts/puppet/modules/lma_logging_analytics/spec/fixtures/modules/lma_logging_analytics/lib deleted file mode 120000 index 42892ea..0000000 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/spec/fixtures/modules/lma_logging_analytics/lib +++ /dev/null @@ -1 +0,0 @@ -../../../../lib \ No newline at end of file diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/spec/functions/encode_kibana_dashboard_spec.rb b/deployment_scripts/puppet/modules/lma_logging_analytics/spec/functions/encode_kibana_dashboard_spec.rb deleted file mode 100644 index 5449e12..0000000 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/spec/functions/encode_kibana_dashboard_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -require 'spec_helper' -require 'json' - -describe 'encode_kibana_dashboard' do - it "should return a JSON hash" do - should run.with_params('bob', 'admin', 'some title', '{}').and_return(/"user":"bob"/).and_return(/"group":"admin"/) - end - - it "should fail when invalid number of parameters are passed" do - should run.with_params('bob', 'admin', 'some title').and_raise_error(/wrong number of arguments/i) - should run.with_params('bob', 'admin', 'some title', '{}', 'extra').and_raise_error(/wrong number of arguments/i) - end -end - diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/spec/unit/puppet/type/kibana_object_type_spec.rb b/deployment_scripts/puppet/modules/lma_logging_analytics/spec/unit/puppet/type/kibana_object_type_spec.rb new file mode 100644 index 0000000..552b999 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/spec/unit/puppet/type/kibana_object_type_spec.rb @@ -0,0 +1,59 @@ +# Copyright 2016 Mirantis, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +require 'spec_helper' + +describe Puppet::Type.type(:kibana_object) do + context "when setting parameters" do + + it "should fail if elasticsearch url isn't HTTP-based" do + expect { + described_class.new :name => "foo", :url => "example.com", + :content => "{}", :ensure => :present, + :type => 'dashboard' + }.to raise_error(Puppet::Error, /not a valid URL/) + end + + it "should fail if content isn't provided" do + expect { + described_class.new :name => "foo", :url => "http://example.com", + :ensure => :present, :type => 'dashboard' + }.to raise_error(Puppet::Error, /content is required/) + end + + it "should fail if content isn't JSON" do + expect { + described_class.new :name => "foo", :url => "http://example.com/", + :content => "{invalid", :ensure => :present, :type => 'dashboard' + }.to raise_error(Puppet::Error, /Invalid JSON/) + end + + it "should accept valid parameters" do + resource = described_class.new :name => "foo", :url => "http://example.com/", + :content => "{}", :ensure => :present, + :type => 'dashboard' + expect(resource[:name]).to eq('foo') + expect(resource[:url]).to eq('http://example.com/') + expect(resource[:content]).to eq({}) + end + + it "should fail if invalide type is provided" do + expect { + resource = described_class.new :name => "foo", :url => "http://example.com/", + :content => "{}", :ensure => :present, + :type => 'wrong type' + }.to raise_error(Puppet::ResourceError, /Valid values are dashboard, visualization, search, config, index-pattern/) + end + end +end + diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/templates/config.js.erb b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/config.js.erb deleted file mode 100644 index 093d20a..0000000 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/templates/config.js.erb +++ /dev/null @@ -1,25 +0,0 @@ -define(['settings'], -function (Settings) { - return new Settings({ - elasticsearch: "http://" + window.location.hostname + ":<%= @es_port %>", - default_route: '<%= @default_route %>', - kibana_index: "kibana-int", - panel_names: [ - 'histogram', - 'map', - 'goal', - 'table', - 'filtering', - 'timepicker', - 'text', - 'hits', - 'column', - 'trends', - 'bettermap', - 'query', - 'terms', - 'stats', - 'sparklines' - ] - }); -}); diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_kibana.json.erb b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_kibana.json.erb deleted file mode 100644 index 5213657..0000000 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_kibana.json.erb +++ /dev/null @@ -1,7 +0,0 @@ -{ - "settings": { - "number_of_shards": <%= @number_of_shards %>, - "auto_expand_replicas": "0-all" - }, - "template": "<%= @index_prefix %>-*" -} diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_kibana4.json.erb b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_kibana4.json.erb new file mode 100644 index 0000000..fb78f72 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_kibana4.json.erb @@ -0,0 +1,139 @@ +{ + "mappings" : { + "index-pattern" : { + "properties" : { + "fieldFormatMap" : { + "type" : "string" + }, + "fields" : { + "type" : "string" + }, + "intervalName" : { + "type" : "string" + }, + "notExpandable" : { + "type" : "boolean" + }, + "timeFieldName" : { + "type" : "string" + }, + "title" : { + "type" : "string" + } + } + }, + "config" : { + "properties" : { + "buildNum" : { + "type" : "string", + "index" : "not_analyzed" + } + } + }, + "search" : { + "properties" : { + "columns" : { + "type" : "string" + }, + "description" : { + "type" : "string" + }, + "hits" : { + "type" : "integer" + }, + "kibanaSavedObjectMeta" : { + "properties" : { + "searchSourceJSON" : { + "type" : "string" + } + } + }, + "sort" : { + "type" : "string" + }, + "title" : { + "type" : "string" + }, + "version" : { + "type" : "integer" + } + } + }, + "visualization" : { + "properties" : { + "description" : { + "type" : "string" + }, + "kibanaSavedObjectMeta" : { + "properties" : { + "searchSourceJSON" : { + "type" : "string" + } + } + }, + "savedSearchId" : { + "type" : "string" + }, + "title" : { + "type" : "string" + }, + "uiStateJSON" : { + "type" : "string" + }, + "version" : { + "type" : "integer" + }, + "visState" : { + "type" : "string" + } + } + }, + "dashboard" : { + "properties" : { + "description" : { + "type" : "string" + }, + "hits" : { + "type" : "integer" + }, + "kibanaSavedObjectMeta" : { + "properties" : { + "searchSourceJSON" : { + "type" : "string" + } + } + }, + "optionsJSON" : { + "type" : "string" + }, + "panelsJSON" : { + "type" : "string" + }, + "timeFrom" : { + "type" : "string" + }, + "timeRestore" : { + "type" : "boolean" + }, + "timeTo" : { + "type" : "string" + }, + "title" : { + "type" : "string" + }, + "uiStateJSON" : { + "type" : "string" + }, + "version" : { + "type" : "integer" + } + } + } + }, + "settings": { + "number_of_shards": <%= @number_of_shards %>, + "auto_expand_replicas": "0-all" + }, + "template": "<%= @template %>" +} + diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_log.json.erb b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_log.json.erb index 54340b8..95a3563 100644 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_log.json.erb +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_log.json.erb @@ -110,5 +110,5 @@ "number_of_shards": <%= @number_of_shards %>, "number_of_replicas": <%= @number_of_replicas %> }, - "template": "<%= @index_prefix %>-*" + "template": "<%= @template %>" } diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_notification.json.erb b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_notification.json.erb index bf34266..02b23c5 100644 --- a/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_notification.json.erb +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/es_template_notification.json.erb @@ -107,5 +107,5 @@ "number_of_shards": <%= @number_of_shards %>, "number_of_replicas": <%= @number_of_replicas %> }, - "template": "<%= @index_prefix %>-*" + "template": "<%= @template %>" } diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4.yaml.erb b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4.yaml.erb new file mode 100644 index 0000000..b92d423 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4.yaml.erb @@ -0,0 +1,4 @@ +elasticsearch.url: "<%= @es_scheme %>://<%= @es_host %>:<%= @es_port %>" +server.host: <%= @listen_address %> +server.port: <%= @listen_port %> +kibana.defaultAppId: "dashboard/Logs" diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/config.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/config.json new file mode 100644 index 0000000..e17715f --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/config.json @@ -0,0 +1 @@ +{"buildNum" : 9892, "defaultIndex" : "log-*"} diff --git a/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/dashboard_logs.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/dashboard_logs.json new file mode 100644 index 0000000..e3db200 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/dashboard_notifications.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/dashboard_notifications.json new file mode 100644 index 0000000..201a203 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/index-pattern_logs.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/index-pattern_logs.json new file mode 100644 index 0000000..432f1c9 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/index-pattern_notifications.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/index-pattern_notifications.json new file mode 100644 index 0000000..84dc492 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/search_logs.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/search_logs.json new file mode 100644 index 0000000..3da81d2 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/search_notifications.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/search_notifications.json new file mode 100644 index 0000000..47e9b87 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_EVENT-TYPE-BREAKDOWN.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_EVENT-TYPE-BREAKDOWN.json new file mode 100644 index 0000000..0ccbcf7 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_HOST-BREAKDOWN.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_HOST-BREAKDOWN.json new file mode 100644 index 0000000..71dc39d --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SEVERITY.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SEVERITY.json new file mode 100644 index 0000000..4ac44ec --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SOURCE.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_LOG-MESSAGES-OVER-TIME-PER-SOURCE.json new file mode 100644 index 0000000..2ca7c05 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SEVERITY.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SEVERITY.json new file mode 100644 index 0000000..7dfa485 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SOURCE.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_NOTIFICATIONS-OVER-TIME-PER-SOURCE.json new file mode 100644 index 0000000..98df8d5 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_NOTIFICATIONS-PER-SEVERITY.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_NOTIFICATIONS-PER-SEVERITY.json new file mode 100644 index 0000000..4a7c361 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-ROLE.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-ROLE.json new file mode 100644 index 0000000..4c6bbe8 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-SEVERITY.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_NUMBER-OF-LOG-MESSAGES-PER-SEVERITY.json new file mode 100644 index 0000000..e447b7e --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_SOURCE-BREAKDOWN.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_SOURCE-BREAKDOWN.json new file mode 100644 index 0000000..d1d75ae --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_TOP-10-HOSTS.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_TOP-10-HOSTS.json new file mode 100644 index 0000000..797a8b4 --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_TOP-10-PROGRAMS.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_TOP-10-PROGRAMS.json new file mode 100644 index 0000000..f65457d --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_TOP-10-SOURCES.json b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_objects/visualization_TOP-10-SOURCES.json new file mode 100644 index 0000000..966056a --- /dev/null +++ b/deployment_scripts/puppet/modules/lma_logging_analytics/templates/kibana4_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/deployment_tasks.yaml b/deployment_tasks.yaml index 737cd84..3b03264 100644 --- a/deployment_tasks.yaml +++ b/deployment_tasks.yaml @@ -21,6 +21,7 @@ - elasticsearch-virtual-ip - elasticsearch-haproxy - elasticsearch-installation + - provision-kibana-index - kibana-installation requires: [deploy_start] required_for: [deploy_end] @@ -32,7 +33,24 @@ type: group version: 2.0.0 role: [elasticsearch_kibana] - tasks: *common_tasks + tasks: + - hiera + - setup_repositories + - fuel_pkgs + - globals + - tools + - logging + - netconfig + - hosts + - elasticsearch-check-configuration + - elasticsearch-hiera + - elasticsearch-firewall + - elasticsearch-cluster + - elasticsearch-cluster-haproxy + - elasticsearch-virtual-ip + - elasticsearch-haproxy + - elasticsearch-installation + - kibana-installation requires: [deploy_start, primary-elasticsearch_kibana] required_for: [deploy_end] parameters: @@ -140,10 +158,25 @@ reexecute_on: - deploy_changes +# In order to automatically import dashboards, this is mandatory to create and +# configure the Kibana index before Kibana4 starts. +- id: provision-kibana-index + type: puppet + version: 2.0.0 + requires: [elasticsearch-installation] + required_for: [deploy_end] + parameters: + puppet_manifest: puppet/manifests/kibana_index_configuration.pp + puppet_modules: puppet/modules:/etc/puppet/modules + timeout: 600 + - id: kibana-installation type: puppet version: 2.0.0 - requires: [elasticsearch-haproxy] + cross-depends: + - name: provision-kibana-index + role: [primary-elasticsearch_kibana] + requires: [elasticsearch-installation, provision-kibana-index] required_for: [deploy_end] parameters: puppet_manifest: puppet/manifests/kibana.pp diff --git a/pre_build_hook b/pre_build_hook index 2e99d65..ad65d95 100755 --- a/pre_build_hook +++ b/pre_build_hook @@ -6,15 +6,11 @@ set -eux # Puppet manifests CONCAT_TARBALL_URL="https://forgeapi.puppetlabs.com/v3/files/puppetlabs-concat-1.2.4.tar.gz" STDLIB_TARBALL_URL="https://forgeapi.puppetlabs.com/v3/files/puppetlabs-stdlib-4.7.0.tar.gz" -NGINX_TARBALL_URL="https://forgeapi.puppetlabs.com/v3/files/jfryman-nginx-0.2.2.tar.gz" ELASTICSEARCH_TARBALL_URL="https://forgeapi.puppetlabs.com/v3/files/elasticsearch-elasticsearch-0.10.1.tar.gz" # Dependency for Elasticsearch 0.10.x DATACAT_TARBALL_URL="https://forgeapi.puppetlabs.com/v3/files/richardc-datacat-0.6.2.tar.gz" FIREWALL_TARBALL_URL="https://forgeapi.puppetlabs.com/v3/files/puppetlabs-firewall-1.7.2.tar.gz" -# Kibana 3 sources -KIBANA_TARBALL_URL="https://download.elasticsearch.org/kibana/kibana/kibana-3.1.3.tar.gz" - TZ_VERSION="2016d-0ubuntu0.14.04_all" # Packages needed to install JRE headless @@ -26,7 +22,8 @@ download_package http://mirrors.kernel.org/ubuntu/pool/main/p/pcsc-lite/libpcscl http://mirrors.kernel.org/ubuntu/pool/main/c/ca-certificates-java/ca-certificates-java_20130815ubuntu1_all.deb \ http://security.ubuntu.com/ubuntu/pool/main/o/openjdk-7/openjdk-7-jre-headless_7u101-2.6.6-0ubuntu0.14.04.1_amd64.deb \ http://mirrors.kernel.org/ubuntu/pool/main/c/ca-certificates-java/ca-certificates-java_20130815ubuntu1_all.deb \ - https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.7.4.deb + https://download.elastic.co/kibana/kibana/kibana_4.5.1_amd64.deb \ + https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/deb/elasticsearch/2.3.3/elasticsearch-2.3.3.deb # Download curator and dependencies download_package http://packages.elasticsearch.org/curator/3/debian/pool/main/p/python/python-elasticsearch-curator_3.3.0_all.deb \ @@ -37,15 +34,10 @@ download_package http://packages.elasticsearch.org/curator/3/debian/pool/main/p/ # Install puppet manifests download_puppet_module "concat" "$CONCAT_TARBALL_URL" download_puppet_module "stdlib" "$STDLIB_TARBALL_URL" -download_puppet_module "nginx" "$NGINX_TARBALL_URL" download_puppet_module "elasticsearch" "$ELASTICSEARCH_TARBALL_URL" download_puppet_module "firewall" "$FIREWALL_TARBALL_URL" download_puppet_module "datacat" "$DATACAT_TARBALL_URL" -# Untar kibana -KIBANA_FOLDER="${MODULES_DIR}/lma_logging_analytics/files/kibana/src" -mkdir -p "${KIBANA_FOLDER}" -wget -qO- "${KIBANA_TARBALL_URL}" | tar -C "${KIBANA_FOLDER}" --strip-components=1 -xz # Update tzdata-java package to remove strict dependency on tzdata (see LP bug #1560436) ROOT="$(dirname "$(readlink -f "$0")")"