prometheus-splash 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +642 -8
- data/assets/images/detail_prom_splash.png +0 -0
- data/assets/images/logo_splash.png +0 -0
- data/assets/images/logo_splash_reduce.png +0 -0
- data/assets/images/prom_pg_logs.png +0 -0
- data/bin/splash +98 -10
- data/config/splash.yml +2 -14
- data/lib/splash/backends/file.rb +11 -5
- data/lib/splash/backends/redis.rb +28 -6
- data/lib/splash/commands.rb +25 -20
- data/lib/splash/config.rb +11 -7
- data/lib/splash/constants.rb +22 -2
- data/lib/splash/logs.rb +7 -0
- data/lib/splash/orchestrator.rb +33 -1
- data/lib/splash/templates.rb +13 -2
- data/lib/splash/transports/rabbitmq.rb +23 -6
- data/lib/splash/transports.rb +3 -3
- data/prometheus-splash.gemspec +2 -1
- data/templates/report.txt +2 -1
- metadata +20 -2
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/bin/splash
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby -W:no-deprecated
|
2
|
-
|
2
|
+
require 'socket'
|
3
|
+
require 'yaml'
|
4
|
+
require 'thread'
|
3
5
|
|
4
6
|
begin
|
5
7
|
require 'prometheus/client'
|
@@ -20,6 +22,7 @@ require 'splash/helpers'
|
|
20
22
|
require 'splash/config'
|
21
23
|
require 'splash/templates'
|
22
24
|
require 'splash/backends'
|
25
|
+
require 'splash/transports'
|
23
26
|
|
24
27
|
require 'splash/commands'
|
25
28
|
require 'splash/logs'
|
@@ -38,21 +41,24 @@ module CLISplash
|
|
38
41
|
include Splash::Config
|
39
42
|
include Splash::Backends
|
40
43
|
|
41
|
-
desc "
|
44
|
+
desc "execute NAME", "run for command/sequence or ack result"
|
42
45
|
long_desc <<-LONGDESC
|
43
|
-
|
44
|
-
with --no-trace prevent storing execution trace in
|
46
|
+
execute command or sequence or ack result
|
47
|
+
with --no-trace prevent storing execution trace in configured backend (see config file)
|
45
48
|
with --ack, notify errorcode=0 to Prometheus PushGateway
|
46
49
|
with --no-notify, bypass Prometheus notification
|
50
|
+
with --no-callback, never execute callback (:on_failure, :on_success)
|
51
|
+
never follow sequences
|
47
52
|
LONGDESC
|
48
53
|
option :trace, :type => :boolean, :default => true
|
49
54
|
option :ack, :type => :boolean, negate: false
|
50
55
|
option :notify, :type => :boolean, :default => true
|
51
|
-
|
56
|
+
option :callback, :type => :boolean, :default => true
|
57
|
+
def execute(name)
|
52
58
|
if is_root? then
|
53
59
|
command = Splash::CommandWrapper::new(name)
|
54
60
|
command.ack if options[:ack]
|
55
|
-
command.call_and_notify trace: options[:trace], notify: options[:notify]
|
61
|
+
command.call_and_notify trace: options[:trace], notify: options[:notify], callback: options[:callback]
|
56
62
|
else
|
57
63
|
$stderr.puts "Command wrapping need to be run as root"
|
58
64
|
exit 60
|
@@ -124,14 +130,24 @@ module CLISplash
|
|
124
130
|
|
125
131
|
|
126
132
|
desc "lastrun COMMAND", "Show last running result for specific configured command COMMAND"
|
133
|
+
long_desc <<-LONGDESC
|
134
|
+
Show last running result for specific configured command COMMAND
|
135
|
+
with --hostname <HOSTNAME>, an other Splash monitored server (only with Redis backend configured)
|
136
|
+
LONGDESC
|
137
|
+
option :hostname, :type => :string
|
127
138
|
def lastrun(command)
|
139
|
+
backend = get_backend :execution_trace
|
140
|
+
redis = (backend.class == Splash::Backends::Redis)? true : false
|
141
|
+
if not redis and options[:hostname] then
|
142
|
+
$stderr.puts "Remote execution report request only possible with Redis backend"
|
143
|
+
end
|
128
144
|
list = get_config.commands
|
129
145
|
if list.keys.include? command.to_sym then
|
130
146
|
print "Splash command #{command} previous execution report:\n\n"
|
131
|
-
|
132
|
-
|
133
|
-
if backend.exist?
|
134
|
-
print backend.get
|
147
|
+
req = { :key => command}
|
148
|
+
req[:hostname] = options[:hostname] if options[:hostname]
|
149
|
+
if backend.exist? req then
|
150
|
+
print backend.get req
|
135
151
|
else
|
136
152
|
puts "Command not already runned."
|
137
153
|
end
|
@@ -141,11 +157,58 @@ module CLISplash
|
|
141
157
|
end
|
142
158
|
end
|
143
159
|
|
160
|
+
desc "getreportlist COMMAND", "list all executions report results "
|
161
|
+
long_desc <<-LONGDESC
|
162
|
+
Show configured commands
|
163
|
+
with --pattern <SEARCH>, search type string, wilcard * (group) ? (char)
|
164
|
+
with --hostname <HOSTNAME>, an other Splash monitored server (only with Redis backend configured)
|
165
|
+
with --all, get all execution report for all servers (only with Redis backend configured)
|
166
|
+
--all and --hostname are exclusives
|
167
|
+
LONGDESC
|
168
|
+
option :pattern, :type => :string
|
169
|
+
option :hostname, :type => :string
|
170
|
+
option :all, :type => :boolean, :negate => false
|
171
|
+
def getreportlist
|
172
|
+
if options[:hostname] and options[:all] then
|
173
|
+
$stderr.puts "--all option imcompatible with --hostname"
|
174
|
+
exit 40
|
175
|
+
end
|
176
|
+
backend = get_backend :execution_trace
|
177
|
+
redis = (backend.class == Splash::Backends::Redis)? true : false
|
178
|
+
if not redis and (options[:hostname] or options[:all]) then
|
179
|
+
$stderr.puts "Remote execution report request only possible with Redis backend"
|
180
|
+
exit 40
|
181
|
+
end
|
182
|
+
pattern = (options[:pattern])? options[:pattern] : '*'
|
183
|
+
if options[:all] then
|
184
|
+
res = backend.listall pattern
|
185
|
+
elsif options[:hostname]
|
186
|
+
res = backend.list pattern, options[:hostname]
|
187
|
+
else
|
188
|
+
res = backend.list pattern
|
189
|
+
end
|
190
|
+
print "List of Executions reports :\n\n"
|
191
|
+
puts "Not reports found" if res.empty?
|
192
|
+
res.each do |item|
|
193
|
+
if options[:all]
|
194
|
+
host,command = item.split('#')
|
195
|
+
puts " * Command : #{command} @ host : #{host}"
|
196
|
+
else
|
197
|
+
puts " * Command : #{item}"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
|
144
204
|
end
|
145
205
|
|
146
206
|
|
207
|
+
|
208
|
+
|
147
209
|
class CLIController < Thor
|
148
210
|
include Splash::LogsMonitor::DaemonController
|
211
|
+
include Splash::Transports
|
149
212
|
|
150
213
|
option :foreground, :type => :boolean
|
151
214
|
desc "start", "Starting Logs Monitor Daemon"
|
@@ -166,6 +229,26 @@ module CLISplash
|
|
166
229
|
exit errorcode
|
167
230
|
end
|
168
231
|
|
232
|
+
desc "ping HOSTNAME", "send a ping to HOSTNAME daemon over transport (need an active tranport), Typicallly RabbitMQ"
|
233
|
+
def ping(hostname=Socket.gethostname)
|
234
|
+
puts "ctrl+c for interrupt"
|
235
|
+
queue = "splash.#{Socket.gethostname}.returncli"
|
236
|
+
order = {:verb => :ping, :payload => {:hostname => Socket.gethostname}, :return_to => queue}
|
237
|
+
|
238
|
+
lock = Mutex.new
|
239
|
+
condition = ConditionVariable.new
|
240
|
+
begin
|
241
|
+
get_default_subscriber(queue: queue).subscribe(timeout: 10) do |delivery_info, properties, payload|
|
242
|
+
puts YAML::load(payload)
|
243
|
+
lock.synchronize { condition.signal }
|
244
|
+
end
|
245
|
+
get_default_client.publish queue: "splash.#{hostname}.input", message: order.to_yaml
|
246
|
+
lock.synchronize { condition.wait(lock) }
|
247
|
+
rescue Interrupt
|
248
|
+
puts "Splash : ping : Interrupted by user. "
|
249
|
+
exit 33
|
250
|
+
end
|
251
|
+
end
|
169
252
|
|
170
253
|
end
|
171
254
|
|
@@ -177,6 +260,11 @@ module CLISplash
|
|
177
260
|
include Splash::Helpers
|
178
261
|
|
179
262
|
desc "setup", "Setup installation fo Splash"
|
263
|
+
long_desc <<-LONGDESC
|
264
|
+
Setup installation fo Splash
|
265
|
+
with --preserve, preserve from reinstallation of the config
|
266
|
+
LONGDESC
|
267
|
+
option :preserve, :type => :boolean
|
180
268
|
def setup
|
181
269
|
errorcode = run_as_root :setupsplash
|
182
270
|
exit errorcode
|
data/config/splash.yml
CHANGED
@@ -5,19 +5,7 @@
|
|
5
5
|
:templates:
|
6
6
|
:execution:
|
7
7
|
:path: /etc/splash_execution_report.tpl
|
8
|
-
:tokens:
|
9
|
-
- :date
|
10
|
-
- :cmd_name
|
11
|
-
- :cmd_line
|
12
|
-
- :stdout
|
13
|
-
- :stderr
|
14
|
-
- :desc
|
15
|
-
- :status
|
16
|
-
- :exec_time
|
17
8
|
:backends:
|
18
|
-
:list:
|
19
|
-
- :file
|
20
|
-
- :redis
|
21
9
|
:stores:
|
22
10
|
:execution_trace:
|
23
11
|
:type: :file
|
@@ -94,5 +82,5 @@
|
|
94
82
|
:logs:
|
95
83
|
- :log: /tmp/test
|
96
84
|
:pattern: ERROR
|
97
|
-
- :log: /
|
98
|
-
:pattern:
|
85
|
+
- :log: /tmp/test2
|
86
|
+
:pattern: ERROR
|
data/lib/splash/backends/file.rb
CHANGED
@@ -8,25 +8,31 @@ module Splash
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def list(pattern='*')
|
11
|
-
|
11
|
+
pattern = suffix_trace(pattern)
|
12
|
+
return Dir.glob("#{@path}/#{pattern}").map{|item| ::File.basename(item,".trace") }
|
12
13
|
end
|
13
14
|
|
14
15
|
def get(options)
|
15
|
-
return ::File.readlines("#{@path}/#{options[:key]}").join
|
16
|
+
return ::File.readlines("#{@path}/#{suffix_trace(options[:key])}").join
|
16
17
|
end
|
17
18
|
|
18
19
|
def put(options)
|
19
|
-
::File.open("#{@path}/#{options[:key]}", 'w') { |file|
|
20
|
+
::File.open("#{@path}/#{suffix_trace(options[:key])}", 'w') { |file|
|
20
21
|
file.write options[:value]
|
21
22
|
}
|
22
23
|
end
|
23
24
|
|
24
25
|
def del(options)
|
25
|
-
::File.unlink("#{@path}/#{options[:key]}") if File.exist?("#{@path}/#{options[:key]}")
|
26
|
+
::File.unlink("#{@path}/#{suffix_trace(options[:key])}") if File.exist?("#{@path}/#{suffix_trace(options[:key])}")
|
26
27
|
end
|
27
28
|
|
28
29
|
def exist?(options)
|
29
|
-
return ::File.exist?("#{@path}/#{options[:key]}")
|
30
|
+
return ::File.exist?("#{@path}/#{suffix_trace(options[:key])}")
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def suffix_trace(astring)
|
35
|
+
return "#{astring}.trace"
|
30
36
|
end
|
31
37
|
|
32
38
|
end
|
@@ -1,30 +1,39 @@
|
|
1
1
|
require "redis"
|
2
|
+
require "socket"
|
2
3
|
|
3
4
|
module Splash
|
4
5
|
module Backends
|
5
6
|
class Redis
|
6
7
|
include Splash::Config
|
7
8
|
def initialize(store)
|
9
|
+
@hostname = Socket.gethostname
|
8
10
|
@config = get_config[:backends][:stores][store]
|
9
11
|
@store = ::Redis.new :host => @config[:host], :port => @config[:port], :db => @config[:base].to_i
|
10
12
|
@redis_cli_cmd = `which redis-cli`
|
11
13
|
@store.auth(@config[:auth]) if @config[:auth]
|
12
14
|
end
|
13
15
|
|
14
|
-
def list(pattern='*')
|
15
|
-
return @store.keys
|
16
|
+
def list(pattern='*', hostname = @hostname)
|
17
|
+
return @store.keys("#{hostname}##{pattern}").map{|item| item = remove_hostname(item)}
|
18
|
+
end
|
19
|
+
|
20
|
+
def listall(pattern='*')
|
21
|
+
return @store.keys(pattern)
|
16
22
|
end
|
17
23
|
|
18
24
|
def get(options)
|
19
|
-
|
25
|
+
hostname = (options[:hostname])? options[:hostname] : @hostname
|
26
|
+
return @store.get(prefix_hostname(options[:key],hostname))
|
20
27
|
end
|
21
28
|
|
22
29
|
def put(options)
|
23
|
-
|
30
|
+
hostname = (options[:hostname])? options[:hostname] : @hostname
|
31
|
+
@store.set prefix_hostname(options[:key],hostname), options[:value]
|
24
32
|
end
|
25
33
|
|
26
34
|
def del(options)
|
27
|
-
|
35
|
+
hostname = (options[:hostname])? options[:hostname] : @hostname
|
36
|
+
@store.del prefix_hostname(options[:key],hostname)
|
28
37
|
end
|
29
38
|
|
30
39
|
def flush
|
@@ -33,7 +42,20 @@ module Splash
|
|
33
42
|
end
|
34
43
|
|
35
44
|
def exist?(options)
|
36
|
-
|
45
|
+
hostname = (options[:hostname])? options[:hostname] : @hostname
|
46
|
+
return ( not @store.get(prefix_hostname(options[:key],hostname)).nil?)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def prefix_hostname(key,hostname)
|
51
|
+
return "#{hostname}##{key}"
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def remove_hostname(astring)
|
56
|
+
result = astring.split("#")
|
57
|
+
result.shift
|
58
|
+
return result.join("#")
|
37
59
|
end
|
38
60
|
|
39
61
|
end
|
data/lib/splash/commands.rb
CHANGED
@@ -47,6 +47,7 @@ module Splash
|
|
47
47
|
def call_and_notify(options)
|
48
48
|
puts "Executing command : '#{@name}' "
|
49
49
|
start = Time.now
|
50
|
+
start_date = DateTime.now.to_s
|
50
51
|
unless options[:trace] then
|
51
52
|
puts " * Traceless execution"
|
52
53
|
if @config.commands[@name.to_sym][:user] then
|
@@ -70,7 +71,8 @@ module Splash
|
|
70
71
|
list_token: @config.execution_template_tokens,
|
71
72
|
template_file: @config.execution_template_path)
|
72
73
|
|
73
|
-
tp.
|
74
|
+
tp.start_date = start_date
|
75
|
+
tp.end_date = DateTime.now.to_s
|
74
76
|
tp.cmd_name = @name
|
75
77
|
tp.cmd_line = @config.commands[@name.to_sym][:command]
|
76
78
|
tp.desc = @config.commands[@name.to_sym][:desc]
|
@@ -79,7 +81,7 @@ module Splash
|
|
79
81
|
tp.stderr = stderr
|
80
82
|
tp.exec_time = time.to_s
|
81
83
|
backend = get_backend :execution_trace
|
82
|
-
key =
|
84
|
+
key = @name
|
83
85
|
backend.put key: key, value: tp.output
|
84
86
|
exit_code = status.exitstatus
|
85
87
|
|
@@ -91,29 +93,32 @@ module Splash
|
|
91
93
|
else
|
92
94
|
puts " * Without Prometheus notification"
|
93
95
|
end
|
94
|
-
|
95
|
-
|
96
|
+
if options[:callback] then
|
97
|
+
on_failure = (@config.commands[@name.to_sym][:on_failure])? @config.commands[@name.to_sym][:on_failure] : false
|
98
|
+
on_success = (@config.commands[@name.to_sym][:on_success])? @config.commands[@name.to_sym][:on_success] : false
|
96
99
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
100
|
+
if on_failure and exit_code > 0 then
|
101
|
+
puts " * On failure callback : #{on_failure}"
|
102
|
+
if @config.commands.keys.include? on_failure then
|
103
|
+
@name = on_failure.to_s
|
104
|
+
call_and_notify options
|
105
|
+
else
|
106
|
+
$stderr.puts "on_failure call error : configuration mistake : #{on_failure} command inexistant."
|
107
|
+
end
|
104
108
|
end
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
109
|
+
if on_success and exit_code == 0 then
|
110
|
+
puts " * On success callback : #{on_success}"
|
111
|
+
if @config.commands.keys.include? on_success then
|
112
|
+
@name = on_success.to_s
|
113
|
+
call_and_notify options
|
114
|
+
else
|
115
|
+
$stderr.puts "on_success call error : configuration mistake : #{on_success} command inexistant."
|
116
|
+
end
|
113
117
|
end
|
118
|
+
else
|
119
|
+
puts " * Without callbacks sequences"
|
114
120
|
end
|
115
121
|
|
116
|
-
|
117
122
|
exit exit_code
|
118
123
|
end
|
119
124
|
end
|
data/lib/splash/config.rb
CHANGED
@@ -18,7 +18,7 @@ module Splash
|
|
18
18
|
self[:prometheus_pushgateway_port] = (config_from_file[:prometheus][:pushgateway][:port])? config_from_file[:prometheus][:pushgateway][:port] : PROMETHEUS_PUSHGATEWAY_PORT
|
19
19
|
self[:daemon_process_name] = (config_from_file[:daemon][:process_name])? config_from_file[:daemon][:process_name] : DAEMON_PROCESS_NAME
|
20
20
|
self[:daemon_logmon_scheduling] = (config_from_file[:daemon][:logmon_scheduling])? config_from_file[:daemon][:logmon_scheduling] : DAEMON_LOGMON_SCHEDULING
|
21
|
-
self[:execution_template_tokens] =
|
21
|
+
self[:execution_template_tokens] = EXECUTION_TEMPLATE_TOKENS_LIST
|
22
22
|
self[:execution_template_path] = (config_from_file[:templates][:execution][:path])? config_from_file[:templates][:execution][:path] : EXECUTION_TEMPLATE
|
23
23
|
self[:pid_path] = (config_from_file[:daemon][:paths][:pid_path])? config_from_file[:daemon][:paths][:pid_path] : DAEMON_PID_PATH
|
24
24
|
self[:trace_path] = (config_from_file[:daemon][:paths][:trace_path])? config_from_file[:daemon][:paths][:trace_path] : TRACE_PATH
|
@@ -58,7 +58,7 @@ module Splash
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def transports
|
61
|
-
return self[:
|
61
|
+
return self[:transports]
|
62
62
|
end
|
63
63
|
|
64
64
|
def daemon_logmon_scheduling
|
@@ -137,12 +137,16 @@ module Splash
|
|
137
137
|
conf_in_path = search_file_in_gem "prometheus-splash", "config/splash.yml"
|
138
138
|
full_res = 0
|
139
139
|
puts "Splash -> setup : "
|
140
|
-
|
141
|
-
|
142
|
-
|
140
|
+
unless options[:preserve] then
|
141
|
+
print "* Installing Configuration file : #{CONFIG_FILE} : "
|
142
|
+
if install_file source: conf_in_path, target: CONFIG_FILE, mode: "644", owner: Configuration.user_root, group: Configuration.group_root then
|
143
|
+
puts "[OK]"
|
144
|
+
else
|
145
|
+
full_res =+ 1
|
146
|
+
puts "[KO]"
|
147
|
+
end
|
143
148
|
else
|
144
|
-
|
145
|
-
puts "[KO]"
|
149
|
+
puts "Config file preservation."
|
146
150
|
end
|
147
151
|
config = get_config
|
148
152
|
report_in_path = search_file_in_gem "prometheus-splash", "templates/report.txt"
|
data/lib/splash/constants.rb
CHANGED
@@ -1,30 +1,50 @@
|
|
1
1
|
module Splash
|
2
2
|
module Constants
|
3
|
-
VERSION = "0.0
|
3
|
+
VERSION = "0.1.0"
|
4
4
|
|
5
|
+
# the path to th config file, not overridable by config
|
5
6
|
CONFIG_FILE = "/etc/splash.yml"
|
7
|
+
# the default execution trace_path if backend file
|
6
8
|
TRACE_PATH="/var/run/splash"
|
7
9
|
|
10
|
+
|
11
|
+
# default scheduling criteria for log monitoring
|
8
12
|
DAEMON_LOGMON_SCHEDULING={ :every => '20s'}
|
13
|
+
# the display name of daemon in proc info (ps/top)
|
9
14
|
DAEMON_PROCESS_NAME="Splash : daemon."
|
15
|
+
# the default pid file path
|
10
16
|
DAEMON_PID_PATH="/var/run"
|
17
|
+
# the default pid file name
|
11
18
|
DAEMON_PID_FILE="splash.pid"
|
19
|
+
# the default sdtout trace file
|
12
20
|
DAEMON_STDOUT_TRACE="stdout.txt"
|
21
|
+
# the default sdterr trace file
|
13
22
|
DAEMON_STDERR_TRACE="stderr.txt"
|
14
23
|
|
24
|
+
# the Author name
|
15
25
|
AUTHOR="Romain GEORGES"
|
26
|
+
# the maintainer mail
|
16
27
|
EMAIL = "gems@ultragreen.net"
|
28
|
+
# legal Copyright (c) 2020 Copyright Utragreen All Rights Reserved.
|
17
29
|
COPYRIGHT="Ultragreen (c) 2020"
|
30
|
+
# type of licence
|
18
31
|
LICENSE="BSD-2-Clause"
|
19
32
|
|
33
|
+
# the default prometheus pushgateway host
|
20
34
|
PROMETHEUS_PUSHGATEWAY_HOST = "localhost"
|
35
|
+
# the default prometheus pushgateway port
|
21
36
|
PROMETHEUS_PUSHGATEWAY_PORT = "9091"
|
22
37
|
|
38
|
+
# the default path fo execution report template
|
23
39
|
EXECUTION_TEMPLATE="/etc/splash_execution_report.tpl"
|
24
|
-
EXECUTION_TEMPLATE_TOKENS_LIST = [:date,:cmd_name,:cmd_line,:stdout,:stderr,:desc,:status,:exec_time]
|
25
40
|
|
41
|
+
# the list of authorized tokens for template, carefull override,
|
42
|
+
EXECUTION_TEMPLATE_TOKENS_LIST = [:end_date,:start_date,:cmd_name,:cmd_line,:stdout,:stderr,:desc,:status,:exec_time]
|
43
|
+
|
44
|
+
# backends default settings
|
26
45
|
BACKENDS_STRUCT = { :list => [:file,:redis],
|
27
46
|
:stores => { :execution_trace => { :type => :file, :path => "/var/run/splash" }}}
|
47
|
+
# transports default settings
|
28
48
|
TRANSPORTS_STRUCT = { :list => [:rabbitmq],
|
29
49
|
:active => :rabbitmq,
|
30
50
|
:rabbitmq => { :url => 'amqp://localhost/'} }
|