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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e6fae61b205672ab555b7cd28f0c0bfc0c48bacbaa81f9696a7ce16ef9eaa2e
4
- data.tar.gz: e9167d60ea4537298014c7af7ee5214ff124d66b1b880925b18069e3a2e5db88
3
+ metadata.gz: 4f2d1cf627c0fd2371da011a6a97a24e82498b9a28b3d4d0485e185841bf7438
4
+ data.tar.gz: e0982026ea749cad8366f420e88cd376bcc8bd0a45e0ec292cc1b9a8237764c2
5
5
  SHA512:
6
- metadata.gz: 5b7e241e27d99e1ca480d387a1c87a86583113d2393756200dc1b167b069b7c24253c911a6dfd05c352f821c3d5e4c691a74a2ace2611f6adf08c545d76019aa
7
- data.tar.gz: 6c5c3579c210e000bdac1f9220b0b89d5bb6e0f1997ea48061d7fe8734546689f18b22fa5d083c4a3fb36e6333b7cdf05637f3dd4c4b5d62ed0988050d758b26
6
+ metadata.gz: b43dcf0493e86ac31da666c4a68c8f2f22f804231f1fd6c0bcc98e3235605e80a4c8e8def976a7c4bf1c54110bdbfe0e67d64040c9d857d23dc16a324cdd1826
7
+ data.tar.gz: 18b7dea993feea9e1a276bf02b5542d98a772754eb68b113bde17ba5f69ec9c346eaa56520d8b960aa658ba1cc4b53a17dd5f7e4af256f8d07b404131573acd4
data/Rakefile CHANGED
@@ -27,6 +27,7 @@ CLOBBER.include('*.tmp', 'build/*','#*#')
27
27
  content = File::readlines(File.join(File.dirname(__FILE__), 'prometheus-splash.gemspec')).join
28
28
  spec = eval(content)
29
29
 
30
+
30
31
  RSpec::Core::RakeTask.new('spec')
31
32
 
32
33
  YARD::Rake::YardocTask.new do |t|
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 "wrap NAME", "wrapping for command or ack result"
41
+ desc "run NAME", "run for command/sequence or ack result"
37
42
  long_desc <<-LONGDESC
38
- wrapping for command or ack result
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
- listc.keys.each do |command|
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
- filename = "#{get_config[:trace_path]}/#{command}_trace.last"
96
- if File::exist? filename then
97
- system("cat #{filename}")
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
- result = Splash::LogScanner::new
170
- result.analyse
171
- p result.output
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
@@ -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
- :logs:
14
- - :log: /tmp/test
15
- :pattern: ERROR
16
- - :log: /var/log/message
17
- :pattern: error
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
- :daemon:
31
- :user: daemon
32
- :group: daemon
33
- :process_name: "Splash : Prometheus logs monitoring."
34
- :paths:
35
- :pid_path: /tmp
36
- :trace_path: /tmp/splash
37
- :files:
38
- :stdout_trace: stdout.txt
39
- :stderr_trace: stderr.txt
40
- :pid_file: splash.pid
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
@@ -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
- registry = Prometheus::Client.registry
33
- url = "http://#{@config.prometheus_pushgateway_host}:#{@config.prometheus_pushgateway_port}"
34
- metric = Prometheus::Client::Gauge.new(:errorcode, docstring: 'SPLASH metric batch errorcode')
35
- registry.register(metric)
36
- metric.set(value)
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
- filename = "#{@config[:trace_path]}/#{@name}_trace.last"
71
- File.open(filename, 'w') { |file| file.write(tp.output) }
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
- notify(exit_code)
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
@@ -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[:daemon_user] = (config_from_file[:daemon][:user])? config_from_file[:daemon][:user] : DAEMON_USER
19
- self[:execution_template_tokens] = (config_from_file[:templates][:execution][:tokens])? config_from_file[:templates][:execution][:tokens] : TOKENS_LIST
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[:daemon_group] = (config_from_file[:daemon][:group])? config_from_file[:daemon][:group] : DAEMON_GROUP
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] : PID_FILE
25
- self[:stdout_trace] = (config_from_file[:daemon][:files][:stdout_trace])? config_from_file[:daemon][:files][:stdout_trace] : STDOUT_TRACE
26
- self[:stderr_trace] = (config_from_file[:daemon][:files][:stderr_trace])? config_from_file[:daemon][:files][:stderr_trace] : 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: "root", group: "wheel" then
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: "root", group: "wheel" then
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: "root", group: "wheel" then
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: "777", owner: config.daemon_user, group: config.daemon_group then
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: "root", group: "wheel")
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: "root", group: "wheel")
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.daemon_user, group: config.daemon_group)
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
@@ -1,22 +1,35 @@
1
1
  module Splash
2
2
  module Constants
3
- VERSION = "0.0.2"
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
- PID_FILE="splash.pid"
10
- STDOUT_TRACE="stdout.txt"
11
- STDERR_TRACE="stderr.txt"
12
- DAEMON_PROCESS_NAME="Splash : Prometheus logs monitoring."
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
- TOKENS_LIST = [:date,:cmd_name,:cmd_line,:stdout,:stderr,:desc,:status]
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
@@ -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
- result = LogScanner::new
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
@@ -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] _options the list of options, keys are symbols
43
- # @option _options [String] :description the description of the process, use for $0
44
- # @option _options [String] :pid_file the pid filenam
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::Application
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::Application
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
- uid = Etc.getpwnam(options[:daemon_user]).uid
92
- gid = Etc.getgrnam(options[:daemon_group]).gid
93
- Process::UID.change_privilege(uid)
94
- # Process::GID.change_privilege(gid)
95
- $stdout.reopen(options[:stdout_trace], "w")
96
- $stderr.reopen(options[:stderr_trace], "w")
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]
@@ -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
- @metric = Prometheus::Client::Gauge.new(:logerror, docstring: 'SPLASH metric log error', labels: [:log ])
11
- @registry.register(@metric)
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] = :mssing
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
- @metric.set(item[:count], labels: { log: item[:log] })
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
- Prometheus::Client::Push.new('Splash').add(@registry)
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
@@ -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
@@ -6,6 +6,7 @@ Command : %%CMD_NAME%%
6
6
  full command line : %%CMD_LINE%%
7
7
  Description : %%DESC%%
8
8
  errorcode : %%STATUS%%
9
+ Execution time (sec) : %%EXEC_TIME%%
9
10
 
10
11
  STDOUT:
11
12
  -------
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.2
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-04 00:00:00.000000000 Z
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 for Services or
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