prometheus-splash 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +1 -0
- data/bin/splash +90 -10
- data/config/splash.yml +75 -17
- data/lib/splash/backends.rb +12 -0
- data/lib/splash/backends/file.rb +35 -0
- data/lib/splash/backends/redis.rb +42 -0
- data/lib/splash/commands.rb +55 -14
- data/lib/splash/config.rb +65 -26
- data/lib/splash/constants.rb +22 -9
- data/lib/splash/controller.rb +2 -13
- data/lib/splash/helpers.rb +34 -14
- data/lib/splash/logs.rb +27 -6
- data/lib/splash/orchestrator.rb +49 -0
- data/lib/splash/transports.rb +18 -0
- data/lib/splash/transports/rabbitmq.rb +45 -0
- data/prometheus-splash.gemspec +4 -2
- data/spec/templates_spec.rb +72 -0
- data/templates/report.txt +1 -0
- metadata +43 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f2d1cf627c0fd2371da011a6a97a24e82498b9a28b3d4d0485e185841bf7438
|
4
|
+
data.tar.gz: e0982026ea749cad8366f420e88cd376bcc8bd0a45e0ec292cc1b9a8237764c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b43dcf0493e86ac31da666c4a68c8f2f22f804231f1fd6c0bcc98e3235605e80a4c8e8def976a7c4bf1c54110bdbfe0e67d64040c9d857d23dc16a324cdd1826
|
7
|
+
data.tar.gz: 18b7dea993feea9e1a276bf02b5542d98a772754eb68b113bde17ba5f69ec9c346eaa56520d8b960aa658ba1cc4b53a17dd5f7e4af256f8d07b404131573acd4
|
data/Rakefile
CHANGED
data/bin/splash
CHANGED
@@ -5,6 +5,8 @@ begin
|
|
5
5
|
require 'prometheus/client'
|
6
6
|
require 'prometheus/client/push'
|
7
7
|
require 'thor'
|
8
|
+
require 'rufus-scheduler'
|
9
|
+
|
8
10
|
rescue Gem::GemNotFoundException
|
9
11
|
$stderr.puts "Loadind error, it's like you try to run Splash, with a lake of dependencies."
|
10
12
|
$stderr.puts "If you run on RVM, please run with rvmsudo and not with sudo."
|
@@ -17,9 +19,11 @@ require 'splash/constants'
|
|
17
19
|
require 'splash/helpers'
|
18
20
|
require 'splash/config'
|
19
21
|
require 'splash/templates'
|
22
|
+
require 'splash/backends'
|
20
23
|
|
21
24
|
require 'splash/commands'
|
22
25
|
require 'splash/logs'
|
26
|
+
require 'splash/orchestrator'
|
23
27
|
require 'splash/controller'
|
24
28
|
|
25
29
|
#inhibit warning : due to prometheus-client call to URI.encode warning
|
@@ -32,20 +36,23 @@ module CLISplash
|
|
32
36
|
|
33
37
|
class Commands < Thor
|
34
38
|
include Splash::Config
|
39
|
+
include Splash::Backends
|
35
40
|
|
36
|
-
desc "
|
41
|
+
desc "run NAME", "run for command/sequence or ack result"
|
37
42
|
long_desc <<-LONGDESC
|
38
|
-
|
43
|
+
Running command or sequence or ack result
|
39
44
|
with --no-trace prevent storing execution trace in TRACE_PATH (see config file)
|
40
45
|
with --ack, notify errorcode=0 to Prometheus PushGateway
|
46
|
+
with --no-notify, bypass Prometheus notification
|
41
47
|
LONGDESC
|
42
48
|
option :trace, :type => :boolean, :default => true
|
43
49
|
option :ack, :type => :boolean, negate: false
|
50
|
+
option :notify, :type => :boolean, :default => true
|
44
51
|
def wrap(name)
|
45
52
|
if is_root? then
|
46
53
|
command = Splash::CommandWrapper::new(name)
|
47
54
|
command.ack if options[:ack]
|
48
|
-
command.call_and_notify trace: options[:trace]
|
55
|
+
command.call_and_notify trace: options[:trace], notify: options[:notify]
|
49
56
|
else
|
50
57
|
$stderr.puts "Command wrapping need to be run as root"
|
51
58
|
exit 60
|
@@ -53,6 +60,31 @@ module CLISplash
|
|
53
60
|
end
|
54
61
|
|
55
62
|
|
63
|
+
|
64
|
+
desc "treeview", "Show commands sequence tree"
|
65
|
+
def treeview(command, depht = 0)
|
66
|
+
puts "Command : #{command.to_s}" if depht == 0
|
67
|
+
cmd = get_config.commands[command.to_sym]
|
68
|
+
if cmd[:on_failure] then
|
69
|
+
print " " * depht + " "
|
70
|
+
puts "* on failure => #{cmd[:on_failure]}"
|
71
|
+
treeview(cmd[:on_failure], depht+2)
|
72
|
+
end
|
73
|
+
if cmd[:on_success] then
|
74
|
+
print " " * depht + " "
|
75
|
+
puts "* on success => #{cmd[:on_success]}"
|
76
|
+
treeview(cmd[:on_success],depht+2)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
|
56
88
|
desc "list", "Show configured commands"
|
57
89
|
long_desc <<-LONGDESC
|
58
90
|
Show configured commands
|
@@ -63,11 +95,13 @@ module CLISplash
|
|
63
95
|
puts "Splash configured commands :"
|
64
96
|
list = get_config.commands
|
65
97
|
puts 'No configured commands found' if list.keys.empty?
|
66
|
-
|
98
|
+
list.keys.each do |command|
|
67
99
|
puts " * #{command.to_s}"
|
68
100
|
if options[:detail] then
|
69
101
|
puts " - command line : '#{list[command][:command]}'"
|
70
102
|
puts " - command description : '#{list[command][:desc]}'"
|
103
|
+
puts " - command failure callback : '#{list[command.to_sym][:on_failure]}'" if list[command.to_sym][:on_failure]
|
104
|
+
puts " - command success callback : '#{list[command.to_sym][:on_success]}'" if list[command.to_sym][:on_success]
|
71
105
|
end
|
72
106
|
end
|
73
107
|
end
|
@@ -80,6 +114,8 @@ module CLISplash
|
|
80
114
|
puts "Splash command : #{command}"
|
81
115
|
puts " - command line : '#{list[command.to_sym][:command]}'"
|
82
116
|
puts " - command description : '#{list[command.to_sym][:desc]}'"
|
117
|
+
puts " - command failure callback : '#{list[command.to_sym][:on_failure]}'" if list[command.to_sym][:on_failure]
|
118
|
+
puts " - command success callback : '#{list[command.to_sym][:on_success]}'" if list[command.to_sym][:on_success]
|
83
119
|
else
|
84
120
|
$stderr.puts "Command not configured"
|
85
121
|
exit 50
|
@@ -92,9 +128,10 @@ module CLISplash
|
|
92
128
|
list = get_config.commands
|
93
129
|
if list.keys.include? command.to_sym then
|
94
130
|
print "Splash command #{command} previous execution report:\n\n"
|
95
|
-
|
96
|
-
|
97
|
-
|
131
|
+
backend = get_backend :execution_trace
|
132
|
+
key = "#{command}_trace.last"
|
133
|
+
if backend.exist? key: key then
|
134
|
+
print backend.get key: key
|
98
135
|
else
|
99
136
|
puts "Command not already runned."
|
100
137
|
end
|
@@ -163,12 +200,25 @@ module CLISplash
|
|
163
200
|
|
164
201
|
|
165
202
|
class Logs < Thor
|
203
|
+
include Splash::Config
|
166
204
|
|
167
205
|
desc "analyse", "analyze logs in config"
|
168
206
|
def analyse
|
169
|
-
|
170
|
-
|
171
|
-
|
207
|
+
results = Splash::LogScanner::new
|
208
|
+
results.analyse
|
209
|
+
puts "SPlash Configured logs status :"
|
210
|
+
full_status = true
|
211
|
+
results.output.each do |result|
|
212
|
+
status = (result[:status] == :clean)? "OK": "KO"
|
213
|
+
puts " * Log : #{result[:log]} : [#{status}]"
|
214
|
+
puts " - Detected pattern : #{result[:pattern]}"
|
215
|
+
puts " - detailled Status : #{result[:status].to_s}"
|
216
|
+
puts " count = #{result[:count]}" if result[:status] == :matched
|
217
|
+
puts " nb lines = #{result[:lines]}" if result[:status] != :missing
|
218
|
+
full_status = false unless result[:status] == :clean
|
219
|
+
end
|
220
|
+
display_status = (full_status)? "OK": "KO"
|
221
|
+
puts "Global Status : [#{display_status}]"
|
172
222
|
end
|
173
223
|
|
174
224
|
desc "monitor", "monitor logs in config"
|
@@ -178,6 +228,36 @@ module CLISplash
|
|
178
228
|
result.notify
|
179
229
|
end
|
180
230
|
|
231
|
+
desc "show LOG", "show configured log monitoring for LOG"
|
232
|
+
def show(log)
|
233
|
+
log_record_set = get_config.logs.select{|item| item[:log] == log }
|
234
|
+
unless log_record_set.empty? then
|
235
|
+
record = log_record_set.first
|
236
|
+
puts "Splash log monitor : #{record[:log]}"
|
237
|
+
puts " -> pattern : /#{record[:pattern]}/"
|
238
|
+
else
|
239
|
+
$stderr.puts "log not configured"
|
240
|
+
exit 50
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
desc "list", "Show configured logs monitoring"
|
245
|
+
long_desc <<-LONGDESC
|
246
|
+
Show configured logs monitoring
|
247
|
+
with --detail, show logs monitor details
|
248
|
+
LONGDESC
|
249
|
+
option :detail, :type => :boolean
|
250
|
+
def list
|
251
|
+
puts "Splash configured log monitoring :"
|
252
|
+
log_record_set = get_config.logs
|
253
|
+
puts 'No configured commands found' if log_record_set.empty?
|
254
|
+
log_record_set.each do |record|
|
255
|
+
puts " * log monitor : #{record[:log]}"
|
256
|
+
if options[:detail] then
|
257
|
+
puts " -> pattern : /#{record[:pattern]}/"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
181
261
|
|
182
262
|
end
|
183
263
|
end
|
data/config/splash.yml
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# Splash Configuration
|
1
2
|
:splash:
|
3
|
+
|
4
|
+
### Main Configuration
|
2
5
|
:templates:
|
3
6
|
:execution:
|
4
7
|
:path: /etc/splash_execution_report.tpl
|
@@ -10,31 +13,86 @@
|
|
10
13
|
- :stderr
|
11
14
|
- :desc
|
12
15
|
- :status
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
:
|
16
|
+
- :exec_time
|
17
|
+
:backends:
|
18
|
+
:list:
|
19
|
+
- :file
|
20
|
+
- :redis
|
21
|
+
:stores:
|
22
|
+
:execution_trace:
|
23
|
+
:type: :file
|
24
|
+
:path: /tmp/splash
|
25
|
+
# :execution_trace:
|
26
|
+
# :type: :redis
|
27
|
+
# :host: localhost
|
28
|
+
# :port: 6379
|
29
|
+
# #:auth: "mykey"
|
30
|
+
# :base: 1
|
31
|
+
:transports:
|
32
|
+
:active: :rabbitmq
|
33
|
+
:rabbitmq:
|
34
|
+
:url: amqp://127.0.0.1
|
35
|
+
:daemon:
|
36
|
+
:logmon_scheduling:
|
37
|
+
:every: 20s
|
38
|
+
:process_name: "Splash : daemon."
|
39
|
+
:paths:
|
40
|
+
:pid_path: /tmp
|
41
|
+
:trace_path: /tmp/splash
|
42
|
+
:files:
|
43
|
+
:stdout_trace: stdout.txt
|
44
|
+
:stderr_trace: stderr.txt
|
45
|
+
:pid_file: splash.pid
|
18
46
|
:prometheus:
|
19
47
|
:pushgateway:
|
20
48
|
:host: "localhost"
|
21
49
|
:port: 9091
|
50
|
+
|
51
|
+
|
52
|
+
### configuration of commands and scheduling
|
22
53
|
:commands:
|
54
|
+
:id_root:
|
55
|
+
:desc: run id command on root
|
56
|
+
:command: id root
|
57
|
+
:true_test:
|
58
|
+
:desc: "test command returning true : 0"
|
59
|
+
:command: "true"
|
60
|
+
:schedule:
|
61
|
+
:every: "1h"
|
62
|
+
:on_failure: :ls_slash_tmp
|
63
|
+
:on_success: :pwd
|
23
64
|
:false_test:
|
24
|
-
:desc: "test command"
|
65
|
+
:desc: "test command returning false > 0"
|
25
66
|
:command: "false"
|
67
|
+
:schedule:
|
68
|
+
:every: "1h"
|
69
|
+
:on_failure: :ls_slash_tmp
|
70
|
+
:on_success: :pwd
|
26
71
|
:ls_slash_tmp:
|
27
72
|
:desc: list file in /tmp
|
28
73
|
:command: ls -al /tmp
|
29
74
|
:user: daemon
|
30
|
-
|
31
|
-
:
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
:
|
36
|
-
|
37
|
-
|
38
|
-
:
|
39
|
-
:
|
40
|
-
|
75
|
+
:on_success: :echo1
|
76
|
+
:pwd:
|
77
|
+
:desc: run pwd
|
78
|
+
:command: pwd
|
79
|
+
:on_success: :echo1
|
80
|
+
:on_failure: :echo2
|
81
|
+
:echo1:
|
82
|
+
:desc: echo 'foo'
|
83
|
+
:command: echo foo
|
84
|
+
:on_failure: :echo3
|
85
|
+
:echo2:
|
86
|
+
:desc: echo 'bar'
|
87
|
+
:command: echo bar
|
88
|
+
:echo3:
|
89
|
+
:desc: echo 'been'
|
90
|
+
:command: echo been
|
91
|
+
|
92
|
+
|
93
|
+
### configuration of monitored logs
|
94
|
+
:logs:
|
95
|
+
- :log: /tmp/test
|
96
|
+
:pattern: ERROR
|
97
|
+
- :log: /var/log/message
|
98
|
+
:pattern: error
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Dir[File.dirname(__FILE__) + '/backends/*.rb'].each {|file| require file }
|
2
|
+
|
3
|
+
module Splash
|
4
|
+
module Backends
|
5
|
+
include Splash::Config
|
6
|
+
def get_backend(store)
|
7
|
+
aclass = "Splash::Backends::#{get_config[:backends][:stores][store][:type].to_s.capitalize}"
|
8
|
+
return Kernel.const_get(aclass)::new(store)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Splash
|
2
|
+
module Backends
|
3
|
+
class File
|
4
|
+
include Splash::Config
|
5
|
+
def initialize(store)
|
6
|
+
@config = get_config[:backends][:stores][store]
|
7
|
+
@path = @config[:path]
|
8
|
+
end
|
9
|
+
|
10
|
+
def list(pattern='*')
|
11
|
+
return Dir.glob(pattern)
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(options)
|
15
|
+
return ::File.readlines("#{@path}/#{options[:key]}").join
|
16
|
+
end
|
17
|
+
|
18
|
+
def put(options)
|
19
|
+
::File.open("#{@path}/#{options[:key]}", 'w') { |file|
|
20
|
+
file.write options[:value]
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def del(options)
|
25
|
+
::File.unlink("#{@path}/#{options[:key]}") if File.exist?("#{@path}/#{options[:key]}")
|
26
|
+
end
|
27
|
+
|
28
|
+
def exist?(options)
|
29
|
+
return ::File.exist?("#{@path}/#{options[:key]}")
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "redis"
|
2
|
+
|
3
|
+
module Splash
|
4
|
+
module Backends
|
5
|
+
class Redis
|
6
|
+
include Splash::Config
|
7
|
+
def initialize(store)
|
8
|
+
@config = get_config[:backends][:stores][store]
|
9
|
+
@store = ::Redis.new :host => @config[:host], :port => @config[:port], :db => @config[:base].to_i
|
10
|
+
@redis_cli_cmd = `which redis-cli`
|
11
|
+
@store.auth(@config[:auth]) if @config[:auth]
|
12
|
+
end
|
13
|
+
|
14
|
+
def list(pattern='*')
|
15
|
+
return @store.keys pattern
|
16
|
+
end
|
17
|
+
|
18
|
+
def get(options)
|
19
|
+
return @store.get(options[:key])
|
20
|
+
end
|
21
|
+
|
22
|
+
def put(options)
|
23
|
+
@store.set options[:key], options[:value]
|
24
|
+
end
|
25
|
+
|
26
|
+
def del(options)
|
27
|
+
@store.del options[:key]
|
28
|
+
end
|
29
|
+
|
30
|
+
def flush
|
31
|
+
`#{@redis_cli_cmd} -n 3 flushdb`
|
32
|
+
# @@store.flushdb
|
33
|
+
end
|
34
|
+
|
35
|
+
def exist?(options)
|
36
|
+
return ( not @store.get(options[:key]).nil?)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/splash/commands.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'open3'
|
2
2
|
require 'date'
|
3
|
-
|
3
|
+
require 'socket'
|
4
4
|
|
5
5
|
module Splash
|
6
6
|
class CommandWrapper
|
7
7
|
include Splash::Templates
|
8
8
|
include Splash::Config
|
9
9
|
include Splash::Helpers
|
10
|
+
include Splash::Backends
|
10
11
|
|
11
12
|
def initialize(name)
|
12
13
|
@config = get_config
|
@@ -15,6 +16,12 @@ module Splash
|
|
15
16
|
$stderr.puts "Splash : command #{@name} is not defined in configuration"
|
16
17
|
exit 40
|
17
18
|
end
|
19
|
+
@registry = Prometheus::Client.registry
|
20
|
+
@url = "http://#{@config.prometheus_pushgateway_host}:#{@config.prometheus_pushgateway_port}"
|
21
|
+
@metric_exitcode = Prometheus::Client::Gauge.new(:errorcode, docstring: 'SPLASH metric batch errorcode')
|
22
|
+
@metric_time = Prometheus::Client::Gauge.new(:exectime, docstring: 'SPLASH metric batch execution time')
|
23
|
+
@registry.register(@metric_exitcode)
|
24
|
+
@registry.register(@metric_time)
|
18
25
|
end
|
19
26
|
|
20
27
|
def ack
|
@@ -23,39 +30,42 @@ module Splash
|
|
23
30
|
exit 0
|
24
31
|
end
|
25
32
|
|
26
|
-
def notify(value)
|
33
|
+
def notify(value,time)
|
27
34
|
unless verify_service host: @config.prometheus_pushgateway_host ,port: @config.prometheus_pushgateway_port then
|
28
35
|
$stderr.puts "Prometheus PushGateway Service IS NOT running"
|
29
36
|
$stderr.puts "Exit without notification."
|
30
37
|
exit 30
|
31
38
|
end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
Prometheus::Client::Push.new(@name, nil, url).add(registry)
|
38
|
-
puts "Prometheus Gateway notified."
|
39
|
+
@metric_exitcode.set(value)
|
40
|
+
@metric_time.set(time)
|
41
|
+
hostname = Socket.gethostname
|
42
|
+
Prometheus::Client::Push.new(@name, hostname, @url).add(@registry)
|
43
|
+
puts " * Prometheus Gateway notified."
|
39
44
|
end
|
40
45
|
|
41
46
|
|
42
47
|
def call_and_notify(options)
|
43
48
|
puts "Executing command : '#{@name}' "
|
49
|
+
start = Time.now
|
44
50
|
unless options[:trace] then
|
45
|
-
puts "Traceless execution"
|
51
|
+
puts " * Traceless execution"
|
46
52
|
if @config.commands[@name.to_sym][:user] then
|
53
|
+
puts " * Execute with user : #{@config.commands[@name.to_sym][:user]}."
|
47
54
|
system("sudo -u #{@config.commands[@name.to_sym][:user]} #{@config.commands[@name.to_sym][:command]} > /dev/null 2>&1")
|
48
55
|
else
|
49
56
|
system("#{@config.commands[@name.to_sym][:command]} > /dev/null 2>&1")
|
50
57
|
end
|
58
|
+
time = Time.now - start
|
51
59
|
exit_code = $?.exitstatus
|
52
60
|
else
|
53
|
-
puts "Tracefull execution"
|
61
|
+
puts " * Tracefull execution"
|
54
62
|
if @config.commands[@name.to_sym][:user] then
|
63
|
+
puts " * Execute with user : #{@config.commands[@name.to_sym][:user]}."
|
55
64
|
stdout, stderr, status = Open3.capture3("sudo -u #{@config.commands[@name.to_sym][:user]} #{@config.commands[@name.to_sym][:command]}")
|
56
65
|
else
|
57
66
|
stdout, stderr, status = Open3.capture3(@config.commands[@name.to_sym][:command])
|
58
67
|
end
|
68
|
+
time = Time.now - start
|
59
69
|
tp = Template::new(
|
60
70
|
list_token: @config.execution_template_tokens,
|
61
71
|
template_file: @config.execution_template_path)
|
@@ -67,12 +77,43 @@ module Splash
|
|
67
77
|
tp.status = status.to_s
|
68
78
|
tp.stdout = stdout
|
69
79
|
tp.stderr = stderr
|
70
|
-
|
71
|
-
|
80
|
+
tp.exec_time = time.to_s
|
81
|
+
backend = get_backend :execution_trace
|
82
|
+
key = "#{@name}_trace.last"
|
83
|
+
backend.put key: key, value: tp.output
|
72
84
|
exit_code = status.exitstatus
|
85
|
+
|
73
86
|
end
|
74
87
|
|
75
|
-
|
88
|
+
puts " => exitcode #{exit_code}"
|
89
|
+
if options[:notify] then
|
90
|
+
notify(exit_code,time.to_i)
|
91
|
+
else
|
92
|
+
puts " * Without Prometheus notification"
|
93
|
+
end
|
94
|
+
on_failure = (@config.commands[@name.to_sym][:on_failure])? @config.commands[@name.to_sym][:on_failure] : false
|
95
|
+
on_success = (@config.commands[@name.to_sym][:on_success])? @config.commands[@name.to_sym][:on_success] : false
|
96
|
+
|
97
|
+
if on_failure and exit_code > 0 then
|
98
|
+
puts " * On failure callback : #{on_failure}"
|
99
|
+
if @config.commands.keys.include? on_failure then
|
100
|
+
@name = on_failure.to_s
|
101
|
+
call_and_notify options
|
102
|
+
else
|
103
|
+
$stderr.puts "on_failure call error : configuration mistake : #{on_failure} command inexistant."
|
104
|
+
end
|
105
|
+
end
|
106
|
+
if on_success and exit_code == 0 then
|
107
|
+
puts " * On success callback : #{on_success}"
|
108
|
+
if @config.commands.keys.include? on_success then
|
109
|
+
@name = on_success.to_s
|
110
|
+
call_and_notify options
|
111
|
+
else
|
112
|
+
$stderr.puts "on_success call error : configuration mistake : #{on_success} command inexistant."
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
76
117
|
exit exit_code
|
77
118
|
end
|
78
119
|
end
|
data/lib/splash/config.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
require 'etc'
|
1
2
|
module Splash
|
2
3
|
module Config
|
3
4
|
include Splash::Helpers
|
4
5
|
include Splash::Constants
|
5
6
|
|
6
7
|
|
7
|
-
|
8
|
+
# Class to manage configuration in Splash from Splash::Constants override by Yaml CONFIG
|
8
9
|
class Configuration < Hash
|
9
10
|
include Splash::Constants
|
11
|
+
|
10
12
|
def initialize(config_file=CONFIG_FILE)
|
11
13
|
config_from_file = readconf config_file
|
12
14
|
self[:version] = VERSION
|
@@ -15,24 +17,57 @@ module Splash
|
|
15
17
|
self[:prometheus_pushgateway_host] = (config_from_file[:prometheus][:pushgateway][:host])? config_from_file[:prometheus][:pushgateway][:host] : PROMETHEUS_PUSHGATEWAY_HOST
|
16
18
|
self[:prometheus_pushgateway_port] = (config_from_file[:prometheus][:pushgateway][:port])? config_from_file[:prometheus][:pushgateway][:port] : PROMETHEUS_PUSHGATEWAY_PORT
|
17
19
|
self[:daemon_process_name] = (config_from_file[:daemon][:process_name])? config_from_file[:daemon][:process_name] : DAEMON_PROCESS_NAME
|
18
|
-
self[:
|
19
|
-
self[:execution_template_tokens] = (config_from_file[:templates][:execution][:tokens])? config_from_file[:templates][:execution][:tokens] :
|
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] = (config_from_file[:templates][:execution][:tokens])? config_from_file[:templates][:execution][:tokens] : EXECUTION_TEMPLATE_TOKENS_LIST
|
20
22
|
self[:execution_template_path] = (config_from_file[:templates][:execution][:path])? config_from_file[:templates][:execution][:path] : EXECUTION_TEMPLATE
|
21
|
-
self[:
|
22
|
-
self[:pid_path] = (config_from_file[:daemon][:paths][:pid_path])? config_from_file[:daemon][:paths][:pid_path] : PID_PATH
|
23
|
+
self[:pid_path] = (config_from_file[:daemon][:paths][:pid_path])? config_from_file[:daemon][:paths][:pid_path] : DAEMON_PID_PATH
|
23
24
|
self[:trace_path] = (config_from_file[:daemon][:paths][:trace_path])? config_from_file[:daemon][:paths][:trace_path] : TRACE_PATH
|
24
|
-
self[:pid_file] = (config_from_file[:daemon][:files][:pid_file])? config_from_file[:daemon][:files][:pid_file] :
|
25
|
-
self[:stdout_trace] = (config_from_file[:daemon][:files][:stdout_trace])? config_from_file[:daemon][:files][:stdout_trace] :
|
26
|
-
self[:stderr_trace] = (config_from_file[:daemon][:files][:stderr_trace])? config_from_file[:daemon][:files][:stderr_trace] :
|
25
|
+
self[:pid_file] = (config_from_file[:daemon][:files][:pid_file])? config_from_file[:daemon][:files][:pid_file] : DAEMON_PID_FILE
|
26
|
+
self[:stdout_trace] = (config_from_file[:daemon][:files][:stdout_trace])? config_from_file[:daemon][:files][:stdout_trace] : DAEMON_STDOUT_TRACE
|
27
|
+
self[:stderr_trace] = (config_from_file[:daemon][:files][:stderr_trace])? config_from_file[:daemon][:files][:stderr_trace] : DAEMON_STDERR_TRACE
|
28
|
+
|
29
|
+
self[:transports] = {} ; self[:transports].merge! TRANSPORTS_STRUCT ; self[:transports].merge! config_from_file[:transports] if config_from_file[:transports]
|
30
|
+
self[:backends] = {} ; self[:backends].merge! BACKENDS_STRUCT ; self[:backends].merge! config_from_file[:backends] if config_from_file[:backends]
|
31
|
+
|
27
32
|
self[:logs] = (config_from_file[:logs])? config_from_file[:logs] : {}
|
28
33
|
self[:commands] = (config_from_file[:commands])? config_from_file[:commands] : {}
|
29
34
|
|
30
35
|
end
|
31
36
|
|
37
|
+
# @!group accessors on configurations Items
|
38
|
+
|
39
|
+
def Configuration.user_root
|
40
|
+
return Etc.getpwuid(0).name
|
41
|
+
end
|
42
|
+
|
43
|
+
def Configuration.group_root
|
44
|
+
return Etc.getgrgid(0).name
|
45
|
+
end
|
46
|
+
|
47
|
+
def user_root
|
48
|
+
return Configuration.user_root
|
49
|
+
end
|
50
|
+
|
51
|
+
def group_root
|
52
|
+
return Configuration.group_root
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
def backends
|
57
|
+
return self[:backends]
|
58
|
+
end
|
59
|
+
|
60
|
+
def transports
|
61
|
+
return self[:transport]
|
62
|
+
end
|
63
|
+
|
64
|
+
def daemon_logmon_scheduling
|
65
|
+
return self[:daemon_logmon_scheduling]
|
66
|
+
end
|
67
|
+
|
32
68
|
def execution_template_path
|
33
69
|
return self[:execution_template_path]
|
34
70
|
end
|
35
|
-
|
36
71
|
def execution_template_tokens
|
37
72
|
return self[:execution_template_tokens]
|
38
73
|
end
|
@@ -67,14 +102,6 @@ module Splash
|
|
67
102
|
return self[:prometheus_pushgateway_port]
|
68
103
|
end
|
69
104
|
|
70
|
-
def daemon_user
|
71
|
-
return self[:daemon_user]
|
72
|
-
end
|
73
|
-
|
74
|
-
def daemon_group
|
75
|
-
return self[:daemon_group]
|
76
|
-
end
|
77
|
-
|
78
105
|
def full_pid_path
|
79
106
|
return "#{self[:pid_path]}/#{self[:pid_file]}"
|
80
107
|
end
|
@@ -87,6 +114,8 @@ module Splash
|
|
87
114
|
return "#{self[:trace_path]}/#{self[:stderr_trace]}"
|
88
115
|
end
|
89
116
|
|
117
|
+
# @!endgroup
|
118
|
+
|
90
119
|
private
|
91
120
|
def readconf(file = CONFIG_FILE)
|
92
121
|
return YAML.load_file(file)[:splash]
|
@@ -95,18 +124,21 @@ module Splash
|
|
95
124
|
|
96
125
|
end
|
97
126
|
|
98
|
-
|
127
|
+
# factory of Configuration Class instance
|
128
|
+
# @param [String] config_file the path of the YAML Config file
|
129
|
+
# @return [SPlash::Config::Configuration]
|
99
130
|
def get_config(config_file=CONFIG_FILE)
|
100
131
|
return Configuration::new config_file
|
101
132
|
end
|
102
133
|
|
103
|
-
|
134
|
+
# Setup action method for installing Splash
|
135
|
+
# @return [Integer] an errorcode value
|
104
136
|
def setupsplash
|
105
137
|
conf_in_path = search_file_in_gem "prometheus-splash", "config/splash.yml"
|
106
138
|
full_res = 0
|
107
139
|
puts "Splash -> setup : "
|
108
140
|
print "* Installing Configuration file : #{CONFIG_FILE} : "
|
109
|
-
if install_file source: conf_in_path, target: CONFIG_FILE, mode: "644", owner:
|
141
|
+
if install_file source: conf_in_path, target: CONFIG_FILE, mode: "644", owner: Configuration.user_root, group: Configuration.group_root then
|
110
142
|
puts "[OK]"
|
111
143
|
else
|
112
144
|
full_res =+ 1
|
@@ -115,7 +147,7 @@ module Splash
|
|
115
147
|
config = get_config
|
116
148
|
report_in_path = search_file_in_gem "prometheus-splash", "templates/report.txt"
|
117
149
|
print "* Installing template file : #{config.execution_template_path} : "
|
118
|
-
if install_file source: report_in_path, target: config.execution_template_path, mode: "644", owner:
|
150
|
+
if install_file source: report_in_path, target: config.execution_template_path, mode: "644", owner: config.user_root, group: config.group_root then
|
119
151
|
puts "[OK]"
|
120
152
|
else
|
121
153
|
full_res =+ 1
|
@@ -123,7 +155,7 @@ module Splash
|
|
123
155
|
end
|
124
156
|
|
125
157
|
print "* Creating/Checking pid file path : #{config[:pid_path]} : "
|
126
|
-
if make_folder path: config[:pid_path], mode: "644", owner:
|
158
|
+
if make_folder path: config[:pid_path], mode: "644", owner: config.user_root, group: config.group_root then
|
127
159
|
puts "[OK]"
|
128
160
|
else
|
129
161
|
full_res =+ 1
|
@@ -131,7 +163,7 @@ module Splash
|
|
131
163
|
end
|
132
164
|
|
133
165
|
print "* Creating/Checking trace file path : #{config[:trace_path]} : "
|
134
|
-
if make_folder path: config[:trace_path], mode: "
|
166
|
+
if make_folder path: config[:trace_path], mode: "644", owner: config.user_root, group: config.group_root then
|
135
167
|
puts "[OK]"
|
136
168
|
else
|
137
169
|
full_res =+ 1
|
@@ -148,12 +180,14 @@ module Splash
|
|
148
180
|
|
149
181
|
end
|
150
182
|
|
183
|
+
# Sanitycheck action method for testing installation of Splash
|
184
|
+
# @return [Integer] an errorcode value
|
151
185
|
def checkconfig
|
152
186
|
puts "Splash -> sanitycheck : "
|
153
187
|
config = get_config
|
154
188
|
full_res = 0
|
155
189
|
print "* Config file : #{CONFIG_FILE} : "
|
156
|
-
res = verify_file(name: CONFIG_FILE, mode: "644", owner:
|
190
|
+
res = verify_file(name: CONFIG_FILE, mode: "644", owner: config.user_root, group: config.group_root)
|
157
191
|
if res.empty? then
|
158
192
|
print "[OK]\n"
|
159
193
|
else
|
@@ -163,7 +197,7 @@ module Splash
|
|
163
197
|
end
|
164
198
|
|
165
199
|
print "* PID Path : #{config[:pid_path]} : "
|
166
|
-
res = verify_folder(name: config[:pid_path], mode: "644", owner:
|
200
|
+
res = verify_folder(name: config[:pid_path], mode: "644", owner: config.user_root, group: config.group_root)
|
167
201
|
if res.empty? then
|
168
202
|
print "[OK]\n"
|
169
203
|
else
|
@@ -174,7 +208,7 @@ module Splash
|
|
174
208
|
end
|
175
209
|
|
176
210
|
print "* trace Path : #{config[:trace_path]} : "
|
177
|
-
res = verify_folder(name: config[:trace_path], mode: "777", owner: config.
|
211
|
+
res = verify_folder(name: config[:trace_path], mode: "777", owner: config.user_root, group: config.group_root)
|
178
212
|
if res.empty? then
|
179
213
|
print "[OK]\n"
|
180
214
|
else
|
@@ -202,6 +236,11 @@ module Splash
|
|
202
236
|
|
203
237
|
private
|
204
238
|
|
239
|
+
# facilities to find a file in gem path
|
240
|
+
# @param [String] _gem a Gem name
|
241
|
+
# @param [String] _file a file relative path in the gem
|
242
|
+
# @return [String] the path of the file, if found.
|
243
|
+
# @return [False] if not found
|
205
244
|
def search_file_in_gem(_gem,_file)
|
206
245
|
if Gem::Specification.respond_to?(:find_by_name)
|
207
246
|
begin
|
data/lib/splash/constants.rb
CHANGED
@@ -1,22 +1,35 @@
|
|
1
1
|
module Splash
|
2
2
|
module Constants
|
3
|
-
VERSION = "0.0.
|
3
|
+
VERSION = "0.0.3"
|
4
|
+
|
4
5
|
CONFIG_FILE = "/etc/splash.yml"
|
5
|
-
DAEMON_USER = "root"
|
6
|
-
DAEMON_GROUP = "wheel"
|
7
|
-
PID_PATH="/var/run"
|
8
6
|
TRACE_PATH="/var/run/splash"
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
|
8
|
+
DAEMON_LOGMON_SCHEDULING={ :every => '20s'}
|
9
|
+
DAEMON_PROCESS_NAME="Splash : daemon."
|
10
|
+
DAEMON_PID_PATH="/var/run"
|
11
|
+
DAEMON_PID_FILE="splash.pid"
|
12
|
+
DAEMON_STDOUT_TRACE="stdout.txt"
|
13
|
+
DAEMON_STDERR_TRACE="stderr.txt"
|
14
|
+
|
13
15
|
AUTHOR="Romain GEORGES"
|
14
16
|
EMAIL = "gems@ultragreen.net"
|
15
17
|
COPYRIGHT="Ultragreen (c) 2020"
|
16
18
|
LICENSE="BSD-2-Clause"
|
19
|
+
|
17
20
|
PROMETHEUS_PUSHGATEWAY_HOST = "localhost"
|
18
21
|
PROMETHEUS_PUSHGATEWAY_PORT = "9091"
|
22
|
+
|
19
23
|
EXECUTION_TEMPLATE="/etc/splash_execution_report.tpl"
|
20
|
-
|
24
|
+
EXECUTION_TEMPLATE_TOKENS_LIST = [:date,:cmd_name,:cmd_line,:stdout,:stderr,:desc,:status,:exec_time]
|
25
|
+
|
26
|
+
BACKENDS_STRUCT = { :list => [:file,:redis],
|
27
|
+
:stores => { :execution_trace => { :type => :file, :path => "/var/run/splash" }}}
|
28
|
+
TRANSPORTS_STRUCT = { :list => [:rabbitmq],
|
29
|
+
:active => :rabbitmq,
|
30
|
+
:rabbitmq => { :url => 'amqp://localhost/'} }
|
31
|
+
|
32
|
+
|
33
|
+
|
21
34
|
end
|
22
35
|
end
|
data/lib/splash/controller.rb
CHANGED
@@ -5,6 +5,7 @@ module Splash
|
|
5
5
|
include Splash::Constants
|
6
6
|
include Splash::Helpers
|
7
7
|
include Splash::Config
|
8
|
+
include Splash::Orchestrator
|
8
9
|
|
9
10
|
def startdaemon(options = {})
|
10
11
|
config = get_config
|
@@ -17,21 +18,9 @@ module Splash
|
|
17
18
|
unless File::exist? config.full_pid_path then
|
18
19
|
res = daemonize :description => config.daemon_process_name,
|
19
20
|
:pid_file => config.full_pid_path,
|
20
|
-
:daemon_user => config.daemon_user,
|
21
|
-
:daemon_group => config.daemon_group,
|
22
21
|
:stdout_trace => config.full_stdout_trace_path,
|
23
22
|
:stderr_trace => config.full_stderr_trace_path do
|
24
|
-
|
25
|
-
while true
|
26
|
-
begin
|
27
|
-
sleep 5
|
28
|
-
puts "Notify"
|
29
|
-
result.analyse
|
30
|
-
result.notify
|
31
|
-
rescue Errno::ECONNREFUSED
|
32
|
-
$stderr.puts "PushGateway seems to be done, please start it."
|
33
|
-
end
|
34
|
-
end
|
23
|
+
Scheduler::new
|
35
24
|
end
|
36
25
|
if res == 0 then
|
37
26
|
pid = `cat #{config.full_pid_path}`.to_i
|
data/lib/splash/helpers.rb
CHANGED
@@ -7,7 +7,10 @@ module Splash
|
|
7
7
|
module Helpers
|
8
8
|
|
9
9
|
|
10
|
-
|
10
|
+
# facilité pour récupérer un PID depuis une regexp
|
11
|
+
# @param [Hash] options
|
12
|
+
# @option options [String] :pattern une regexp
|
13
|
+
# @return [String] le PID
|
11
14
|
def get_process(options = {})
|
12
15
|
pattern = options[:pattern]
|
13
16
|
res = `ps aux|grep '#{pattern}'|grep -v grep`.to_s
|
@@ -18,7 +21,8 @@ module Splash
|
|
18
21
|
end
|
19
22
|
end
|
20
23
|
|
21
|
-
|
24
|
+
# facilité pour vérifier si le process actif est root
|
25
|
+
# @return [Bool] vrai ou faux
|
22
26
|
def is_root?
|
23
27
|
case (Process.uid)
|
24
28
|
when 0
|
@@ -28,6 +32,9 @@ module Splash
|
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
35
|
+
# facilité pour s'assurer qu'on execute une méthode avec les droits root
|
36
|
+
# @param [Symbol] method a method name th wrap
|
37
|
+
# @return [void] le retour de la méthode wrappée
|
31
38
|
def run_as_root(method)
|
32
39
|
unless is_root?
|
33
40
|
$stderr.puts "You need to be root to execute this subcommands : #{method.to_s}"
|
@@ -39,13 +46,18 @@ module Splash
|
|
39
46
|
end
|
40
47
|
|
41
48
|
# method for daemonize blocks
|
42
|
-
# @param [Hash]
|
43
|
-
# @option
|
44
|
-
# @option
|
49
|
+
# @param [Hash] options the list of options, keys are symbols
|
50
|
+
# @option options [String] :description the description of the process, use for $0
|
51
|
+
# @option options [String] :pid_file the pid filename
|
52
|
+
# @option options [String] :daemon_user the user to change privileges
|
53
|
+
# @option options [String] :daemon_group the group to change privileges
|
54
|
+
# @option options [String] :stderr_trace the path of the file where to redirect STDERR
|
55
|
+
# @option options [String] :stdout_trace the path of the file where to redirect STDOUT
|
56
|
+
# @option options [Bool] :debug option to run foreground
|
45
57
|
# @yield a process definion or block given
|
46
58
|
# @example usage inline
|
47
59
|
# class Test
|
48
|
-
# include Splash::Helpers
|
60
|
+
# include Splash::Helpers
|
49
61
|
# private :daemonize
|
50
62
|
# def initialize
|
51
63
|
# @loop = Proc::new do
|
@@ -62,7 +74,7 @@ module Splash
|
|
62
74
|
#
|
63
75
|
# @example usage block
|
64
76
|
# class Test
|
65
|
-
# include Splash::Helpers
|
77
|
+
# include Splash::Helpers
|
66
78
|
# include Dorsal::Privates
|
67
79
|
# private :daemonize
|
68
80
|
# def initialize
|
@@ -88,15 +100,17 @@ module Splash
|
|
88
100
|
fork do
|
89
101
|
#Process.daemon
|
90
102
|
File.open(options[:pid_file],"w"){|f| f.puts Process.pid } if options[:pid_file]
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
103
|
+
if options[:daemon_user] and options[:daemon_group] then
|
104
|
+
uid = Etc.getpwnam(options[:daemon_user]).uid
|
105
|
+
gid = Etc.getgrnam(options[:daemon_group]).gid
|
106
|
+
Process::UID.change_privilege(uid)
|
107
|
+
# Process::GID.change_privilege(gid)
|
108
|
+
end
|
109
|
+
$stdout.reopen(options[:stdout_trace], "w") if options[:stdout_trace]
|
110
|
+
$stderr.reopen(options[:stderr_trace], "w") if options[:stderr_trace]
|
97
111
|
|
98
112
|
#$0 = options[:description]
|
99
|
-
Process.setproctitle options[:description]
|
113
|
+
Process.setproctitle options[:description] if options[:description]
|
100
114
|
|
101
115
|
yield
|
102
116
|
|
@@ -110,6 +124,9 @@ module Splash
|
|
110
124
|
# @param [Hash] options
|
111
125
|
# @option options [String] :source le chemin source du fichier
|
112
126
|
# @option options [String] :target le chemin cible du fichier
|
127
|
+
# @option options [String] :mode les droits du fichier du type Octal "XXX"
|
128
|
+
# @option options [String] :owner le owner du fichier
|
129
|
+
# @option options [String] :group le groupe du fichier
|
113
130
|
def install_file(options = {})
|
114
131
|
#begin
|
115
132
|
FileUtils::copy options[:source], options[:target] #unless File::exist? options[:target]
|
@@ -124,6 +141,9 @@ module Splash
|
|
124
141
|
# facilité de création de répertoire
|
125
142
|
# @param [Hash] options
|
126
143
|
# @option options [String] :path le répertoire à créer (relatif ou absolut)
|
144
|
+
# @option options [String] :mode les droits du fichier du type Octal "XXX"
|
145
|
+
# @option options [String] :owner le owner du fichier
|
146
|
+
# @option options [String] :group le groupe du fichier
|
127
147
|
def make_folder(options = {})
|
128
148
|
begin
|
129
149
|
FileUtils::mkdir_p options[:path] unless File::exist? options[:path]
|
data/lib/splash/logs.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
1
3
|
module Splash
|
2
4
|
class LogScanner
|
3
5
|
include Splash::Constants
|
@@ -5,10 +7,14 @@ module Splash
|
|
5
7
|
|
6
8
|
def initialize
|
7
9
|
@logs_target = get_config.logs
|
8
|
-
|
10
|
+
@config = get_config
|
9
11
|
@registry = Prometheus::Client.registry
|
10
|
-
@
|
11
|
-
@
|
12
|
+
@metric_count = Prometheus::Client::Gauge.new(:logerrors, docstring: 'SPLASH metric log error', labels: [:log ])
|
13
|
+
@metric_missing = Prometheus::Client::Gauge.new(:logmissing, docstring: 'SPLASH metric log missing', labels: [:log ])
|
14
|
+
@metric_lines = Prometheus::Client::Gauge.new(:loglines, docstring: 'SPLASH metric log lines numbers', labels: [:log ])
|
15
|
+
@registry.register(@metric_count)
|
16
|
+
@registry.register(@metric_missing)
|
17
|
+
@registry.register(@metric_lines)
|
12
18
|
end
|
13
19
|
|
14
20
|
def analyse
|
@@ -18,8 +24,9 @@ module Splash
|
|
18
24
|
if File.exist?(record[:log]) then
|
19
25
|
record[:count] = File.readlines(record[:log]).grep(/#{record[:pattern]}/).size
|
20
26
|
record[:status] = :matched if record[:count] > 0
|
27
|
+
record[:lines] = `wc -l "#{record[:log]}"`.strip.split(/\s+/)[0].to_i unless record[:status] == :missing
|
21
28
|
else
|
22
|
-
record[:status] = :
|
29
|
+
record[:status] = :missing
|
23
30
|
end
|
24
31
|
end
|
25
32
|
end
|
@@ -29,10 +36,24 @@ module Splash
|
|
29
36
|
end
|
30
37
|
|
31
38
|
def notify
|
39
|
+
unless verify_service host: @config.prometheus_pushgateway_host ,port: @config.prometheus_pushgateway_port then
|
40
|
+
$stderr.puts "Prometheus PushGateway Service IS NOT running"
|
41
|
+
$stderr.puts "Exit without notification."
|
42
|
+
exit 30
|
43
|
+
end
|
44
|
+
puts "Sending metrics to Prometheus Pushgateway"
|
32
45
|
@logs_target.each do |item|
|
33
|
-
|
46
|
+
missing = (item[:status] == :missing)? 1 : 0
|
47
|
+
puts " * Sending metrics for #{item[:log]}"
|
48
|
+
@metric_count.set(item[:count], labels: { log: item[:log] })
|
49
|
+
@metric_missing.set(missing, labels: { log: item[:log] })
|
50
|
+
lines = (item[:lines])? item[:lines] : 0
|
51
|
+
@metric_lines.set(lines, labels: { log: item[:log] })
|
34
52
|
end
|
35
|
-
|
53
|
+
hostname = Socket.gethostname
|
54
|
+
url = "http://#{@config.prometheus_pushgateway_host}:#{@config.prometheus_pushgateway_port}"
|
55
|
+
Prometheus::Client::Push.new('Splash',hostname, url).add(@registry)
|
56
|
+
puts "Sending done."
|
36
57
|
end
|
37
58
|
|
38
59
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Splash
|
2
|
+
module Orchestrator
|
3
|
+
|
4
|
+
module SchedulerHooks
|
5
|
+
def on_pre_trigger(job, trigger_time)
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
def on_post_trigger(job, trigger_time)
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
def init_log
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
class Scheduler
|
20
|
+
include Splash::Constants
|
21
|
+
include Splash::Helpers
|
22
|
+
include Splash::Config
|
23
|
+
def initialize
|
24
|
+
@server = Rufus::Scheduler::new
|
25
|
+
@server.extend SchedulerHooks
|
26
|
+
@server.init_log
|
27
|
+
@result = LogScanner::new
|
28
|
+
@server.every '20s' do
|
29
|
+
begin
|
30
|
+
puts "Notify"
|
31
|
+
@result.analyse
|
32
|
+
@result.notify
|
33
|
+
$stdout.flush
|
34
|
+
rescue Errno::ECONNREFUSED
|
35
|
+
$stderr.puts "PushGateway seems to be done, please start it."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
@server.join
|
39
|
+
end
|
40
|
+
|
41
|
+
def terminate
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Dir[File.dirname(__FILE__) + '/transports/*.rb'].each {|file| require file }
|
2
|
+
|
3
|
+
module Splash
|
4
|
+
module Transports
|
5
|
+
include Splash::Config
|
6
|
+
|
7
|
+
def get_default_subscriber
|
8
|
+
aclass = "Splash::Transports::#{get_config[:transports][:active].to_s.capitalize}::Suscriber"
|
9
|
+
return Kernel.const_get(aclass)::new
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_default_client
|
13
|
+
aclass = "Splash::Transports::#{get_config[:transports][:active].to_s.capitalize}::Client"
|
14
|
+
return Kernel.const_get(aclass)::new
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'bunny'
|
2
|
+
module Splash
|
3
|
+
module Transports
|
4
|
+
module RabbitMQ
|
5
|
+
|
6
|
+
class Subscriber
|
7
|
+
def initialize
|
8
|
+
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
class Client
|
14
|
+
def initialize
|
15
|
+
@connection = Bunny.new
|
16
|
+
@connection.start
|
17
|
+
@channel = @connection.create_channel
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def publish(options ={})
|
22
|
+
return @channel.default_exchange.publish(options[:message], :routing_key => options[:queue])
|
23
|
+
end
|
24
|
+
|
25
|
+
def ack
|
26
|
+
return @channel.acknowledge(delivery_info.delivery_tag, false)
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def get(options ={})
|
31
|
+
queue = @channel.queue(options[:queue])
|
32
|
+
delivery_info, properties, payload = queue.pop
|
33
|
+
res = {:message => payload}
|
34
|
+
res[:ack] = delivery_info.delivery_tag if options[:noack]
|
35
|
+
return res
|
36
|
+
end
|
37
|
+
|
38
|
+
def close
|
39
|
+
@connection.close
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/prometheus-splash.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Splash::Constants::VERSION
|
9
9
|
spec.authors = [Splash::Constants::AUTHOR]
|
10
10
|
spec.email = [Splash::Constants::EMAIL]
|
11
|
-
spec.description = %q{Prometheus Logs and Batchs supervision over PushGateway}
|
12
|
-
spec.summary = %q{Supervision with Prometheus of Logs and Asynchronous tasks for Services or Hosts }
|
11
|
+
spec.description = %q{Prometheus Logs and Batchs supervision over PushGateway and commands orchestration}
|
12
|
+
spec.summary = %q{Supervision with Prometheus of Logs and Asynchronous tasks orchestration for Services or Hosts }
|
13
13
|
spec.homepage = "http://www.ultragreen.net"
|
14
14
|
spec.license = Splash::Constants::LICENSE
|
15
15
|
spec.require_paths << 'bin'
|
@@ -21,6 +21,8 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
spec.add_runtime_dependency 'thor','~> 1.0.1'
|
23
23
|
spec.add_runtime_dependency 'prometheus-client','~> 2.0.0'
|
24
|
+
spec.add_runtime_dependency 'rufus-scheduler','~> 3.6.0'
|
25
|
+
spec.add_runtime_dependency 'redis','~> 4.1.3'
|
24
26
|
spec.add_development_dependency 'rake', '~> 13.0.1'
|
25
27
|
spec.add_development_dependency 'rspec', '~> 3.9.0'
|
26
28
|
spec.add_development_dependency 'yard', '~> 0.9.24'
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require_relative '../lib/splash/templates'
|
2
|
+
|
3
|
+
include Splash::Templates
|
4
|
+
|
5
|
+
describe Template do
|
6
|
+
$template_file = "/tmp/template.txt"
|
7
|
+
$nonexistantfile = "/tmp/nonexistant.txt"
|
8
|
+
$template = "Hello %%NAME%% !!"
|
9
|
+
$result = "Hello Romain !!"
|
10
|
+
$goodtoken = :name
|
11
|
+
$badtoken = :surname
|
12
|
+
$value = 'Romain'
|
13
|
+
before :all do
|
14
|
+
`echo "#{$template}" > #{$template_file}`
|
15
|
+
File::unlink($nonexistantfile) if File::exist?($nonexistantfile)
|
16
|
+
end
|
17
|
+
subject { Template }
|
18
|
+
specify { should be_an_instance_of Class }
|
19
|
+
context "Exception case" do
|
20
|
+
it "should raise NoTemplateFile if template file not exist" do
|
21
|
+
expect { Template::new({:list_token => [$goodtoken] , :template_file => $nonexistantfile}) }.to raise_error NoTemplateFile
|
22
|
+
end
|
23
|
+
it "should raise NotAToken if try to send ##{$badtoken} and '#{$badtoken}' not a valid token" do
|
24
|
+
expect { Template::new({ :list_token => [$goodtoken], :template_file => $template_file}).send($badtoken.to_sym)}.to raise_error NotAToken
|
25
|
+
end
|
26
|
+
it "should raise InvalidTokenList if initialized with ['#{$goodtoken}','#{$badtoken}'] tokens list" do
|
27
|
+
expect { Template::new({ :list_token => [$goodtoken,$badtoken] , :template_file => $template_file})}.to raise_error InvalidTokenList
|
28
|
+
end
|
29
|
+
it "should raise NoTemplateFile if template file not exist AND initialized with ['#{$goodtoken}','#{$badtoken}'] tokens list" do
|
30
|
+
expect { Template::new({ :list_token => [$goodtoken,$badtoken] , :template_file => $nonexistantfile})}.to raise_error NoTemplateFile
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "Template <execution> with token '#{$goodtoken}', content = '#{$content}', and ##{$goodtoken}='#{$value}'" do
|
35
|
+
before :all do
|
36
|
+
$test = Template::new({ :list_token => [$goodtoken] , :template_file => $template_file})
|
37
|
+
end
|
38
|
+
context "#content" do
|
39
|
+
specify {expect($test.content).to be_an_instance_of String }
|
40
|
+
it "should have '#{$template}' in #content" do
|
41
|
+
expect( $test.content).to eq($template)
|
42
|
+
end
|
43
|
+
specify {expect($test).to_not respond_to 'content=' }
|
44
|
+
end
|
45
|
+
context "#token_list" do
|
46
|
+
specify {expect($test.list_token).to be_an_instance_of Array }
|
47
|
+
it "should have ['#{$goodtoken}'] in #list_token" do
|
48
|
+
expect($test.list_token).to eq([$goodtoken])
|
49
|
+
end
|
50
|
+
specify { expect($test).to_not respond_to 'token_list=' }
|
51
|
+
end
|
52
|
+
context "virtual (methode_missing) #{$goodtoken}" do
|
53
|
+
specify { expect($test.send($goodtoken.to_sym)).to be_an_instance_of String }
|
54
|
+
specify { expect($test).to respond_to(:name) }
|
55
|
+
specify { $test.name = $value; expect($test.name).to eq($value) }
|
56
|
+
it "should raise ArgumentError if virtual methode '#name=' got non String arguement (accessor)" do
|
57
|
+
expect { $test.name = 1 }.to raise_error ArgumentError
|
58
|
+
end
|
59
|
+
end
|
60
|
+
context "#output" do
|
61
|
+
it "should #output 'Hello Romain !!' if set #name = 'Romain' and msg send #output" do
|
62
|
+
$test.name = 'Romain'
|
63
|
+
expect( $test.output).to eq('Hello Romain !!')
|
64
|
+
end
|
65
|
+
specify { expect($test).to_not respond_to 'output=' }
|
66
|
+
end
|
67
|
+
after :all do
|
68
|
+
File::unlink($template_file) if File::exist?($template_file)
|
69
|
+
$test = nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/templates/report.txt
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prometheus-splash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Romain GEORGES
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-04-
|
11
|
+
date: 2020-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 2.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rufus-scheduler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.6.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.6.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: redis
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 4.1.3
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 4.1.3
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: rake
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,7 +164,8 @@ dependencies:
|
|
136
164
|
- - "~>"
|
137
165
|
- !ruby/object:Gem::Version
|
138
166
|
version: '0.1'
|
139
|
-
description: Prometheus Logs and Batchs supervision over PushGateway
|
167
|
+
description: Prometheus Logs and Batchs supervision over PushGateway and commands
|
168
|
+
orchestration
|
140
169
|
email:
|
141
170
|
- gems@ultragreen.net
|
142
171
|
executables:
|
@@ -150,14 +179,21 @@ files:
|
|
150
179
|
- Rakefile
|
151
180
|
- bin/splash
|
152
181
|
- config/splash.yml
|
182
|
+
- lib/splash/backends.rb
|
183
|
+
- lib/splash/backends/file.rb
|
184
|
+
- lib/splash/backends/redis.rb
|
153
185
|
- lib/splash/commands.rb
|
154
186
|
- lib/splash/config.rb
|
155
187
|
- lib/splash/constants.rb
|
156
188
|
- lib/splash/controller.rb
|
157
189
|
- lib/splash/helpers.rb
|
158
190
|
- lib/splash/logs.rb
|
191
|
+
- lib/splash/orchestrator.rb
|
159
192
|
- lib/splash/templates.rb
|
193
|
+
- lib/splash/transports.rb
|
194
|
+
- lib/splash/transports/rabbitmq.rb
|
160
195
|
- prometheus-splash.gemspec
|
196
|
+
- spec/templates_spec.rb
|
161
197
|
- templates/report.txt
|
162
198
|
- templates/splashd.service
|
163
199
|
- ultragreen_roodi_coding_convention.yml
|
@@ -183,6 +219,7 @@ requirements: []
|
|
183
219
|
rubygems_version: 3.1.2
|
184
220
|
signing_key:
|
185
221
|
specification_version: 4
|
186
|
-
summary: Supervision with Prometheus of Logs and Asynchronous tasks
|
187
|
-
Hosts
|
188
|
-
test_files:
|
222
|
+
summary: Supervision with Prometheus of Logs and Asynchronous tasks orchestration
|
223
|
+
for Services or Hosts
|
224
|
+
test_files:
|
225
|
+
- spec/templates_spec.rb
|