prometheus-splash 0.1.1 → 0.2.0

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: 62507dbefc8ccad97a7388a4527a79991b7224e5d6181d8edc06fcd6299c6791
4
- data.tar.gz: 62fa6ab6b86cd2442a9f3d6e2a4bf3e073f3a2d0a51154dba4fa64590c4b5f54
3
+ metadata.gz: 7065fa547ec467bcde47fcb52c57a05fa0abc5e902e3ce1f9ed3c1ac0f64b0d6
4
+ data.tar.gz: 73cb3e469d7c32adaeebf39987c8c767e2579889bcea5101cdf1492101ffffe6
5
5
  SHA512:
6
- metadata.gz: f651a3c3a6c758ce7939403d16c48d4b8f3666e30ad378c9de2db38a3e5ff7bfaf5565a0ffedf971781305a3098b15e9d5111efa1b4be6db16db8642b43ddbfc
7
- data.tar.gz: fe6b45de95e4ecde64eb7361d4edc6da5268bfebabd312617b44983612155f02a7bc20c6297adf85797abe069350f81bf9cc46ec43ebb3fc493fcdd115306280
6
+ metadata.gz: c390147005809aa6d3fe5aa9975e4f8ca4787fb1a3c359c53e33d21cb50d9329aae48946fcbb8168ee5fbadeba05cf43ca4b2d761435a9b50e60098f30debd2a
7
+ data.tar.gz: e241c29c18a58c9dbd095323b2d2600fe9e30aacd20096e276d508920124b0419c5e7ee24a0bca5b6f34e5eb8424f79739f57443f980972d7e67e94a75e41b88
data/README.md CHANGED
@@ -75,6 +75,11 @@ With :
75
75
  - SERVER : IP or fqdn of the Gateway.
76
76
  - PORT : the specific TCP port of the Gateway.
77
77
 
78
+ If you have already setup, you could use --preserve option to keep your active configuration and report file on place
79
+ This is usefull for automatique Idempotent installation like with Ansible :
80
+
81
+ # splash conf set --preserve
82
+
78
83
 
79
84
  ### Sanitycheck
80
85
 
@@ -475,7 +480,7 @@ If you want to prevent callback execution, as root :
475
480
 
476
481
  #### Display the last execution trace for a command
477
482
 
478
- If you want to view the last execution trace for commande, (run with --trace : default)
483
+ If you want to view the last execution trace for commande, (only if executed with --trace : default)
479
484
 
480
485
  # splash com lastrun
481
486
  Splash command pwd previous execution report:
@@ -500,6 +505,11 @@ If you want to view the last execution trace for commande, (run with --trace :
500
505
 
501
506
  STDERR:
502
507
  -------
508
+
509
+
510
+ Lastrun could receive the --hostname option to get the execution report of command
511
+
512
+
503
513
  ### Advanced Configuration
504
514
 
505
515
  #### Backend configuration
data/config/splash.yml CHANGED
@@ -20,6 +20,8 @@
20
20
  :active: :rabbitmq
21
21
  :rabbitmq:
22
22
  :url: amqp://127.0.0.1
23
+ :port: 5672
24
+ :host: "localhost"
23
25
  :daemon:
24
26
  :logmon_scheduling:
25
27
  :every: 20s
@@ -4,9 +4,16 @@ Dir[File.dirname(__FILE__) + '/backends/*.rb'].each {|file| require file }
4
4
  module Splash
5
5
  module Backends
6
6
  include Splash::Config
7
+ include Splash::Constants
8
+
7
9
  def get_backend(store)
8
- aclass = "Splash::Backends::#{get_config[:backends][:stores][store][:type].to_s.capitalize}"
9
- return Kernel.const_get(aclass)::new(store)
10
+ backend = get_config[:backends][:stores][store][:type].to_s
11
+ aclass = "Splash::Backends::#{backend.capitalize}"
12
+ begin
13
+ return Kernel.const_get(aclass)::new(store)
14
+ rescue
15
+ splash_exit case: :configuration_error, more: "Backend specified for store #{store} inexistant : #{backend}"
16
+ end
10
17
  end
11
18
 
12
19
  end
@@ -6,28 +6,61 @@ module CLISplash
6
6
  include Splash::Config
7
7
  include Splash::Backends
8
8
  include Splash::Exiter
9
+ include Splash::Transports
10
+ include Splash::Templates
9
11
 
10
12
  desc "execute NAME", "run for command/sequence or ack result"
11
13
  long_desc <<-LONGDESC
12
- execute command or sequence or ack result
13
- with --no-trace prevent storing execution trace in configured backend (see config file)
14
- with --ack, notify errorcode=0 to Prometheus PushGateway
15
- with --no-notify, bypass Prometheus notification
16
- with --no-callback, never execute callback (:on_failure, :on_success)
14
+ execute command or sequence or ack result\n
15
+ with --no-trace prevent storing execution trace in configured backend (see config file)\n
16
+ with --ack, notify errorcode=0 to Prometheus PushGateway\n
17
+ with --no-notify, bypass Prometheus notification\n
18
+ with --no-callback, never execute callback (:on_failure, :on_success)\n
17
19
  never follow sequences
20
+ with --hostname, execute on an other Splash daemon node
18
21
  LONGDESC
19
22
  option :trace, :type => :boolean, :default => true
20
23
  option :ack, :type => :boolean, negate: false
21
24
  option :notify, :type => :boolean, :default => true
22
25
  option :callback, :type => :boolean, :default => true
26
+ option :hostname, :type => :string
23
27
  def execute(name)
24
28
  if is_root? then
25
- command = Splash::CommandWrapper::new(name)
26
- if options[:ack] then
27
- splash_exit command.ack
29
+ if options[:hostname] then
30
+ puts "Remote Splash configured commands on #{options[:hostname]}:"
31
+ puts "ctrl+c for interrupt"
32
+ begin
33
+ transport = get_default_client
34
+ if transport.class == Hash and transport.include? :case then
35
+ splash_exit transport
36
+ else
37
+ if options[:ack] then
38
+ res = transport.execute({ :verb => :ack_command,
39
+ payload: {:name => name},
40
+ :return_to => "splash.#{Socket.gethostname}.returncli",
41
+ :queue => "splash.#{options[:hostname]}.input" })
42
+ res[:more] = "Remote command : :ack_command OK"
43
+ splash_exit res
44
+ else
45
+ res = transport.execute({ :verb => :execute_command,
46
+ payload: {:name => name},
47
+ :return_to => "splash.#{Socket.gethostname}.returncli",
48
+ :queue => "splash.#{options[:hostname]}.input" })
49
+ res[:more] = "Remote command : :execute_command Scheduled"
50
+ splash_exit res
51
+ end
52
+ end
53
+ rescue Interrupt
54
+ splash_exit case: :interrupt, more: "Remote command exection"
55
+ end
56
+ else
57
+ command = Splash::CommandWrapper::new(name)
58
+ if options[:ack] then
59
+ splash_exit command.ack
60
+ end
61
+ acase = command.call_and_notify trace: options[:trace], notify: options[:notify], callback: options[:callback]
62
+ splash_exit acase
28
63
  end
29
- acase = command.call_and_notify trace: options[:trace], notify: options[:notify], callback: options[:callback]
30
- splash_exit acase
31
64
  else
32
65
  splash_exit case: :not_root, :more => "Command execution"
33
66
  end
@@ -56,11 +89,31 @@ module CLISplash
56
89
  long_desc <<-LONGDESC
57
90
  Show configured commands
58
91
  with --detail, show command details
92
+ with --hostname, ask other splash daemon via transport
59
93
  LONGDESC
60
94
  option :detail, :type => :boolean
95
+ option :hostname, :type => :string
61
96
  def list
62
- puts "Splash configured commands :"
63
- list = get_config.commands
97
+ list = {}
98
+ if options[:hostname] then
99
+ puts "Remote Splash configured commands on #{options[:hostname]}:"
100
+ puts "ctrl+c for interrupt"
101
+ begin
102
+ transport = get_default_client
103
+ if transport.class == Hash and transport.include? :case then
104
+ splash_exit transport
105
+ else
106
+ list = transport.execute({ :verb => :list_commands,
107
+ :return_to => "splash.#{Socket.gethostname}.returncli",
108
+ :queue => "splash.#{options[:hostname]}.input" })
109
+ end
110
+ rescue Interrupt
111
+ splash_exit case: :interrupt, more: "remote list Command"
112
+ end
113
+ else
114
+ puts "Splash configured commands :"
115
+ list = get_config.commands
116
+ end
64
117
  puts 'No configured commands found' if list.keys.empty?
65
118
  list.keys.each do |command|
66
119
  puts " * #{command.to_s}"
@@ -103,19 +156,27 @@ module CLISplash
103
156
  if not redis and options[:hostname] then
104
157
  splash_exit case: :specific_config_required, :more => "Redis backend is requiered for Remote execution report request"
105
158
  end
106
- list = get_config.commands
107
- if list.keys.include? command.to_sym then
159
+ list = get_config.commands.keys
160
+ if options[:hostname] then
161
+ list = backend.list("*", options[:hostname]).map(&:to_sym)
162
+ end
163
+ if list.include? command.to_sym then
108
164
  print "Splash command #{command} previous execution report:\n\n"
109
165
  req = { :key => command}
110
166
  req[:hostname] = options[:hostname] if options[:hostname]
111
167
  if backend.exist? req then
112
- print backend.get req
168
+ res = backend.get req
169
+ tp = Template::new(
170
+ list_token: get_config.execution_template_tokens,
171
+ template_file: get_config.execution_template_path)
172
+ tp.map YAML::load(res)
173
+ print tp.output
113
174
  else
114
175
  puts "Command not already runned."
115
176
  end
116
177
  splash_exit case: :quiet_exit
117
178
  else
118
- splash_exit case: :command_not_configured
179
+ splash_exit case: :not_found, :more => "Command report never runned remotly" if options[:hostname]
119
180
  end
120
181
  end
121
182
 
@@ -125,11 +186,13 @@ module CLISplash
125
186
  with --pattern <SEARCH>, search type string, wilcard * (group) ? (char)\n
126
187
  with --hostname <HOSTNAME>, an other Splash monitored server (only with Redis backend configured)\n
127
188
  with --all, get all execution report for all servers (only with Redis backend configured)\n
189
+ with --detail, get major informations of each reports
128
190
  --all and --hostname are exclusives
129
191
  LONGDESC
130
192
  option :pattern, :type => :string
131
193
  option :hostname, :type => :string
132
194
  option :all, :type => :boolean, :negate => false
195
+ option :detail, :type => :boolean
133
196
  def getreportlist
134
197
  if options[:hostname] and options[:all] then
135
198
  splash_exit case: :options_incompatibility, more: "--all, --hostname"
@@ -137,7 +200,7 @@ module CLISplash
137
200
  backend = get_backend :execution_trace
138
201
  redis = (backend.class == Splash::Backends::Redis)? true : false
139
202
  if not redis and (options[:hostname] or options[:all]) then
140
- splash_exit case: :redis_back_required, more: "Remote execution report Request"
203
+ splash_exit case: :specific_config_required, more: "Redis Backend requiered for Remote execution report Request"
141
204
  end
142
205
  pattern = (options[:pattern])? options[:pattern] : '*'
143
206
  if options[:all] then
@@ -150,11 +213,23 @@ module CLISplash
150
213
  print "List of Executions reports :\n\n"
151
214
  puts "Not reports found" if res.empty?
152
215
  res.each do |item|
216
+ host = ""
217
+ command = ""
153
218
  if options[:all]
154
219
  host,command = item.split('#')
155
220
  puts " * Command : #{command} @ host : #{host}"
156
221
  else
157
- puts " * Command : #{item}"
222
+ command = item
223
+ puts " * Command : #{command}"
224
+ end
225
+ if options[:detail] then
226
+ req = { :key => command }
227
+ req[:hostname] = host if options[:all]
228
+ res = YAML::load(backend.get(req))
229
+ puts " - Status : #{res[:status]}"
230
+ puts " - Start date : #{res[:start_date]}"
231
+ puts " - End date : #{res[:end_date]}"
232
+ puts " - Execution time : #{res[:exec_time]}"
158
233
  end
159
234
  end
160
235
  splash_exit case: :quiet_exit
@@ -8,19 +8,52 @@ module CLISplash
8
8
 
9
9
 
10
10
  option :foreground, :type => :boolean
11
- desc "start", "Starting Logs Monitor Daemon"
11
+ option :purge, :type => :boolean
12
+ option :scheduling, :type => :boolean, default: true
13
+ long_desc <<-LONGDESC
14
+ Starting Splash Daemon\n
15
+ With --foreground, run Splash in foreground\n
16
+ With --no-scheduling, inhibit commands scheduling\n
17
+ With --purge, Purge Input Queue for Splash Daemon
18
+ LONGDESC
19
+ desc "start", "Starting Splash Daemon"
12
20
  def start
13
- acase = run_as_root :startdaemon
21
+ if options[:purge] then
22
+ transport = get_default_client
23
+ if transport.class == Hash and transport.include? :case then
24
+ splash_exit transport
25
+ else
26
+ queue = "splash.#{Socket.gethostname}.input"
27
+ transport.purge queue: queue
28
+ puts " * Queue : #{queue} purged"
29
+ splash_exit case: :quiet_exit
30
+ end
31
+ end
32
+ acase = run_as_root :startdaemon, options
14
33
  splash_exit acase
15
34
  end
16
35
 
17
- desc "stop", "Stopping Logs Monitor Daemon"
36
+
37
+ desc "purge", "Purge Transport Input queue of Daemon"
38
+ def purge
39
+ transport = get_default_client
40
+ if transport.class == Hash and transport.include? :case then
41
+ splash_exit transport
42
+ else
43
+ queue = "splash.#{Socket.gethostname}.input"
44
+ transport.purge queue: queue
45
+ puts " * Queue : #{queue} purged"
46
+ splash_exit case: :quiet_exit
47
+ end
48
+ end
49
+
50
+ desc "stop", "Stopping Splash Daemon"
18
51
  def stop
19
52
  acase = run_as_root :stopdaemon
20
53
  splash_exit acase
21
54
  end
22
55
 
23
- desc "status", "Logs Monitor Daemon status"
56
+ desc "status", "Splash Daemon status"
24
57
  def status
25
58
  acase = run_as_root :statusdaemon
26
59
  splash_exit acase
@@ -29,19 +62,17 @@ module CLISplash
29
62
  desc "ping HOSTNAME", "send a ping to HOSTNAME daemon over transport (need an active tranport), Typicallly RabbitMQ"
30
63
  def ping(hostname=Socket.gethostname)
31
64
  puts "ctrl+c for interrupt"
32
- queue = "splash.#{Socket.gethostname}.returncli"
33
- order = {:verb => :ping, :payload => {:hostname => Socket.gethostname}, :return_to => queue}
34
-
35
- lock = Mutex.new
36
- condition = ConditionVariable.new
37
65
  begin
38
- get_default_subscriber(queue: queue).subscribe(timeout: 10) do |delivery_info, properties, payload|
39
- puts YAML::load(payload)
40
- lock.synchronize { condition.signal }
66
+ transport = get_default_client
67
+ if transport.class == Hash and transport.include? :case then
68
+ splash_exit transport
69
+ else
70
+ puts transport.execute({ :verb => :ping,
71
+ :payload => {:hostname => Socket.gethostname},
72
+ :return_to => "splash.#{Socket.gethostname}.returncli",
73
+ :queue => "splash.#{hostname}.input" })
74
+ splash_exit case: :quiet_exit
41
75
  end
42
- get_default_client.publish queue: "splash.#{hostname}.input", message: order.to_yaml
43
- lock.synchronize { condition.wait(lock) }
44
- splash_exit case: :quiet_exit
45
76
  rescue Interrupt
46
77
  splash_exit status: :error, case: :interrupt, more: "Ping Command"
47
78
  end
@@ -7,18 +7,20 @@ module Splash
7
7
  include Splash::Backends
8
8
  include Splash::Exiter
9
9
 
10
+
11
+ @@registry = Prometheus::Client.registry
12
+ @@metric_exitcode = Prometheus::Client::Gauge.new(:errorcode, docstring: 'SPLASH metric batch errorcode')
13
+ @@metric_time = Prometheus::Client::Gauge.new(:exectime, docstring: 'SPLASH metric batch execution time')
14
+ @@registry.register(@@metric_exitcode)
15
+ @@registry.register(@@metric_time)
16
+
10
17
  def initialize(name)
11
18
  @config = get_config
19
+ @url = "http://#{@config.prometheus_pushgateway_host}:#{@config.prometheus_pushgateway_port}"
12
20
  @name = name
13
21
  unless @config.commands.keys.include? @name.to_sym then
14
22
  splash_exit case: :not_found, more: "command #{@name} is not defined in configuration"
15
23
  end
16
- @registry = Prometheus::Client.registry
17
- @url = "http://#{@config.prometheus_pushgateway_host}:#{@config.prometheus_pushgateway_port}"
18
- @metric_exitcode = Prometheus::Client::Gauge.new(:errorcode, docstring: 'SPLASH metric batch errorcode')
19
- @metric_time = Prometheus::Client::Gauge.new(:exectime, docstring: 'SPLASH metric batch execution time')
20
- @registry.register(@metric_exitcode)
21
- @registry.register(@metric_time)
22
24
  end
23
25
 
24
26
  def ack
@@ -30,10 +32,10 @@ module Splash
30
32
  unless verify_service host: @config.prometheus_pushgateway_host ,port: @config.prometheus_pushgateway_port then
31
33
  return { :case => :service_dependence_missing, :more => "Prometheus Notification not send."}
32
34
  end
33
- @metric_exitcode.set(value)
34
- @metric_time.set(time)
35
+ @@metric_exitcode.set(value)
36
+ @@metric_time.set(time)
35
37
  hostname = Socket.gethostname
36
- Prometheus::Client::Push.new(@name, hostname, @url).add(@registry)
38
+ Prometheus::Client::Push.new(@name, hostname, @url).add(@@registry)
37
39
  puts " * Prometheus Gateway notified."
38
40
  return { :case => :quiet_exit}
39
41
  end
@@ -66,21 +68,20 @@ module Splash
66
68
  tp = Template::new(
67
69
  list_token: @config.execution_template_tokens,
68
70
  template_file: @config.execution_template_path)
69
-
70
- tp.start_date = start_date
71
- tp.end_date = DateTime.now.to_s
72
- tp.cmd_name = @name
73
- tp.cmd_line = @config.commands[@name.to_sym][:command]
74
- tp.desc = @config.commands[@name.to_sym][:desc]
75
- tp.status = status.to_s
76
- tp.stdout = stdout
77
- tp.stderr = stderr
78
- tp.exec_time = time.to_s
71
+ data = Hash::new
72
+ data[:start_date] = start_date
73
+ data[:end_date] = DateTime.now.to_s
74
+ data[:cmd_name] = @name
75
+ data[:cmd_line] = @config.commands[@name.to_sym][:command]
76
+ data[:desc] = @config.commands[@name.to_sym][:desc]
77
+ data[:status] = status.to_s
78
+ data[:stdout] = stdout
79
+ data[:stderr] = stderr
80
+ data[:exec_time] = time.to_s
79
81
  backend = get_backend :execution_trace
80
82
  key = @name
81
- backend.put key: key, value: tp.output
83
+ backend.put key: key, value: data.to_yaml
82
84
  exit_code = status.exitstatus
83
-
84
85
  end
85
86
 
86
87
  puts " => exitcode #{exit_code}"
data/lib/splash/config.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  # coding: utf-8
2
+ Dir[File.dirname(__FILE__) + '/config/*.rb'].each {|file| require file }
3
+
2
4
  module Splash
3
5
  module Config
4
6
  include Splash::Helpers
5
7
  include Splash::Constants
8
+ include Splash::ConfigUtilities
6
9
 
7
10
 
8
11
  # Class to manage configuration in Splash from Splash::Constants override by Yaml CONFIG
@@ -36,22 +39,6 @@ module Splash
36
39
 
37
40
  # @!group accessors on configurations Items
38
41
 
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
42
 
56
43
  def backends
57
44
  return self[:backends]
@@ -131,142 +118,8 @@ module Splash
131
118
  return Configuration::new config_file
132
119
  end
133
120
 
134
- # Setup action method for installing Splash
135
- # @return [Integer] an errorcode value
136
- def setupsplash
137
- conf_in_path = search_file_in_gem "prometheus-splash", "config/splash.yml"
138
- full_res = 0
139
- puts "Splash -> setup : "
140
- unless options[:preserve] then
141
- print "* Installing Configuration file : #{CONFIG_FILE} : "
142
- if install_file source: conf_in_path, target: CONFIG_FILE, mode: "644", owner: Configuration.user_root, group: Configuration.group_root then
143
- puts "[OK]"
144
- else
145
- full_res =+ 1
146
- puts "[KO]"
147
- end
148
- else
149
- puts "Config file preservation."
150
- end
151
- config = get_config
152
- report_in_path = search_file_in_gem "prometheus-splash", "templates/report.txt"
153
- print "* Installing template file : #{config.execution_template_path} : "
154
- if install_file source: report_in_path, target: config.execution_template_path, mode: "644", owner: config.user_root, group: config.group_root then
155
- puts "[OK]"
156
- else
157
- full_res =+ 1
158
- puts "[KO]"
159
- end
160
-
161
- print "* Creating/Checking pid file path : #{config[:pid_path]} : "
162
- if make_folder path: config[:pid_path], mode: "644", owner: config.user_root, group: config.group_root then
163
- puts "[OK]"
164
- else
165
- full_res =+ 1
166
- puts "[KO]"
167
- end
168
-
169
- print "* Creating/Checking trace file path : #{config[:trace_path]} : "
170
- if make_folder path: config[:trace_path], mode: "644", owner: config.user_root, group: config.group_root then
171
- puts "[OK]"
172
- else
173
- full_res =+ 1
174
- puts "[KO]"
175
- end
176
-
177
- if full_res > 0 then
178
- $stderr.puts " => #{full_res} errors occured"
179
- return { :case => :splash_setup_error}
180
- else
181
- return { :case => :splash_setup_success }
182
- end
183
-
184
- end
185
-
186
- # Sanitycheck action method for testing installation of Splash
187
- # @return [Integer] an errorcode value
188
- def checkconfig
189
- puts "Splash -> sanitycheck : "
190
- config = get_config
191
- full_res = 0
192
- print "* Config file : #{CONFIG_FILE} : "
193
- res = verify_file(name: CONFIG_FILE, mode: "644", owner: config.user_root, group: config.group_root)
194
- if res.empty? then
195
- print "[OK]\n"
196
- else
197
- print "[KO]\n"
198
- full_res =+ 1
199
- puts " pbm => #{res.map {|p| p.to_s}.join(',')}"
200
- end
201
121
 
202
- print "* PID Path : #{config[:pid_path]} : "
203
- res = verify_folder(name: config[:pid_path], mode: "644", owner: config.user_root, group: config.group_root)
204
- if res.empty? then
205
- print "[OK]\n"
206
- else
207
- print "[KO]\n"
208
- full_res =+ 1
209
- puts " pbm => #{res.map {|p| p.to_s}.join(',')}"
210
122
 
211
- end
212
-
213
- print "* trace Path : #{config[:trace_path]} : "
214
- res = verify_folder(name: config[:trace_path], mode: "777", owner: config.user_root, group: config.group_root)
215
- if res.empty? then
216
- print "[OK]\n"
217
- else
218
- print "[KO]\n"
219
- full_res =+ 1
220
- puts " pbm => #{res.map {|p| p.to_s}.join(',')}"
221
- end
222
-
223
- print "* Prometheus PushGateway Service running : "
224
- if verify_service host: config.prometheus_pushgateway_host ,port: config.prometheus_pushgateway_port then
225
- print "[OK]\n"
226
- else
227
- print "[KO]\n"
228
- full_res =+ 1
229
- end
230
-
231
- if full_res > 0 then
232
- $stderr.puts " => #{full_res} errors occured"
233
- return { :case => :splash_sanitycheck_error }
234
- else
235
- return { :case => :splash_sanitycheck_success}
236
- end
237
- end
238
-
239
- private
240
-
241
- # facilities to find a file in gem path
242
- # @param [String] _gem a Gem name
243
- # @param [String] _file a file relative path in the gem
244
- # @return [String] the path of the file, if found.
245
- # @return [False] if not found
246
- def search_file_in_gem(_gem,_file)
247
- if Gem::Specification.respond_to?(:find_by_name)
248
- begin
249
- spec = Gem::Specification.find_by_name(_gem)
250
- rescue LoadError
251
- spec = nil
252
- end
253
- else
254
- spec = Gem.searcher.find(_gem)
255
- end
256
- if spec then
257
- if Gem::Specification.respond_to?(:find_by_name)
258
- res = spec.lib_dirs_glob.split('/')
259
- else
260
- res = Gem.searcher.lib_dirs_for(spec).split('/')
261
- end
262
- res.pop
263
- services_path = res.join('/').concat("/#{_file}")
264
- return services_path if File::exist?(services_path)
265
- return false
266
- else
267
- return false
268
- end
269
- end
270
123
 
271
124
  end
272
125
  end
@@ -0,0 +1,59 @@
1
+ # coding: utf-8
2
+ module Splash
3
+ module ConfigUtilities
4
+ include Splash::Constants
5
+
6
+ # Sanitycheck action method for testing installation of Splash
7
+ # @return [Integer] an errorcode value
8
+ def checkconfig
9
+ puts "Splash -> sanitycheck : "
10
+ config = get_config
11
+ full_res = 0
12
+ print "* Config file : #{CONFIG_FILE} : "
13
+ res = verify_file(name: CONFIG_FILE, mode: "644", owner: config.user_root, group: config.group_root)
14
+ if res.empty? then
15
+ print "[OK]\n"
16
+ else
17
+ print "[KO]\n"
18
+ full_res =+ 1
19
+ puts " pbm => #{res.map {|p| p.to_s}.join(',')}"
20
+ end
21
+
22
+ print "* PID Path : #{config[:pid_path]} : "
23
+ res = verify_folder(name: config[:pid_path], mode: "644", owner: config.user_root, group: config.group_root)
24
+ if res.empty? then
25
+ print "[OK]\n"
26
+ else
27
+ print "[KO]\n"
28
+ full_res =+ 1
29
+ puts " pbm => #{res.map {|p| p.to_s}.join(',')}"
30
+
31
+ end
32
+
33
+ print "* trace Path : #{config[:trace_path]} : "
34
+ res = verify_folder(name: config[:trace_path], mode: "777", owner: config.user_root, group: config.group_root)
35
+ if res.empty? then
36
+ print "[OK]\n"
37
+ else
38
+ print "[KO]\n"
39
+ full_res =+ 1
40
+ puts " pbm => #{res.map {|p| p.to_s}.join(',')}"
41
+ end
42
+
43
+ print "* Prometheus PushGateway Service running : "
44
+ if verify_service host: config.prometheus_pushgateway_host ,port: config.prometheus_pushgateway_port then
45
+ print "[OK]\n"
46
+ else
47
+ print "[KO]\n"
48
+ full_res =+ 1
49
+ end
50
+
51
+ if full_res > 0 then
52
+ $stderr.puts " => #{full_res} errors occured"
53
+ return { :case => :splash_sanitycheck_error }
54
+ else
55
+ return { :case => :splash_sanitycheck_success}
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,62 @@
1
+
2
+ # coding: utf-8
3
+
4
+
5
+ module Splash
6
+ module ConfigUtilities
7
+ include Splash::Constants
8
+ include Splash::Helpers
9
+ # Setup action method for installing Splash
10
+ # @return [Integer] an errorcode value
11
+ def setupsplash
12
+ conf_in_path = search_file_in_gem "prometheus-splash", "config/splash.yml"
13
+ full_res = 0
14
+ puts "Splash -> setup : "
15
+ unless options[:preserve] then
16
+ print "* Installing Configuration file : #{CONFIG_FILE} : "
17
+ # TODO TTY plateform
18
+ if install_file source: conf_in_path, target: CONFIG_FILE, mode: "644", owner: user_root, group: group_root then
19
+ puts "[OK]"
20
+ else
21
+ full_res =+ 1
22
+ puts "[KO]"
23
+ end
24
+ else
25
+ puts "Config file preservation."
26
+ end
27
+ config = get_config
28
+ report_in_path = search_file_in_gem "prometheus-splash", "templates/report.txt"
29
+ print "* Installing template file : #{config.execution_template_path} : "
30
+ if install_file source: report_in_path, target: config.execution_template_path, mode: "644", owner: config.user_root, group: config.group_root then
31
+ puts "[OK]"
32
+ else
33
+ full_res =+ 1
34
+ puts "[KO]"
35
+ end
36
+
37
+ print "* Creating/Checking pid file path : #{config[:pid_path]} : "
38
+ if make_folder path: config[:pid_path], mode: "644", owner: config.user_root, group: config.group_root then
39
+ puts "[OK]"
40
+ else
41
+ full_res =+ 1
42
+ puts "[KO]"
43
+ end
44
+
45
+ print "* Creating/Checking trace file path : #{config[:trace_path]} : "
46
+ if make_folder path: config[:trace_path], mode: "644", owner: config.user_root, group: config.group_root then
47
+ puts "[OK]"
48
+ else
49
+ full_res =+ 1
50
+ puts "[KO]"
51
+ end
52
+
53
+ if full_res > 0 then
54
+ $stderr.puts " => #{full_res} errors occured"
55
+ return { :case => :splash_setup_error}
56
+ else
57
+ return { :case => :splash_setup_success }
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
  module Splash
3
3
  module Constants
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
5
5
 
6
6
  # the path to th config file, not overridable by config
7
7
  CONFIG_FILE = "/etc/splash.yml"
@@ -48,7 +48,7 @@ module Splash
48
48
  # transports default settings
49
49
  TRANSPORTS_STRUCT = { :list => [:rabbitmq],
50
50
  :active => :rabbitmq,
51
- :rabbitmq => { :url => 'amqp://localhost/'} }
51
+ :rabbitmq => { :port => 5672, :host => "localhost"} }
52
52
 
53
53
 
54
54
 
@@ -12,20 +12,19 @@ module Splash
12
12
  unless verify_service host: config.prometheus_pushgateway_host ,port: config.prometheus_pushgateway_port then
13
13
  return {:case => :service_dependence_missing, :more => 'Prometheus Gateway'}
14
14
  end
15
-
16
15
  unless File::exist? config.full_pid_path then
17
16
  res = daemonize :description => config.daemon_process_name,
18
17
  :pid_file => config.full_pid_path,
19
18
  :stdout_trace => config.full_stdout_trace_path,
20
- :stderr_trace => config.full_stderr_trace_path do
21
- Scheduler::new
19
+ :stderr_trace => config.full_stderr_trace_path, :foreground => options[:foreground] do
20
+ Scheduler::new options
22
21
  end
23
22
  if res == 0 then
24
23
  pid = `cat #{config.full_pid_path}`.to_i
25
24
  puts "Splash Daemon Started, with PID : #{pid}"
26
25
  return {:case => :quiet_exit}
27
26
  else
28
- return {:case => :unknown_error, :more => "Splash Daemon loading error"}
27
+ return {:case => :unknown_error, :more => "Splash Daemon loading error, see logs for more details"}
29
28
  end
30
29
 
31
30
  else
data/lib/splash/exiter.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  module Splash
2
3
  module Exiter
3
4
  EXIT_MAP= {
@@ -3,6 +3,15 @@ module Splash
3
3
  module Helpers
4
4
 
5
5
 
6
+
7
+ def user_root
8
+ return Etc.getpwuid(0).name
9
+ end
10
+
11
+ def group_root
12
+ return Etc.getgrgid(0).name
13
+ end
14
+
6
15
  # facilité pour récupérer un PID depuis une regexp
7
16
  # @param [Hash] options
8
17
  # @option options [String] :pattern une regexp
@@ -17,6 +26,39 @@ module Splash
17
26
  end
18
27
  end
19
28
 
29
+
30
+ # facilities to find a file in gem path
31
+ # @param [String] _gem a Gem name
32
+ # @param [String] _file a file relative path in the gem
33
+ # @return [String] the path of the file, if found.
34
+ # @return [False] if not found
35
+ def search_file_in_gem(_gem,_file)
36
+ if Gem::Specification.respond_to?(:find_by_name)
37
+ begin
38
+ spec = Gem::Specification.find_by_name(_gem)
39
+ rescue LoadError
40
+ spec = nil
41
+ end
42
+ else
43
+ spec = Gem.searcher.find(_gem)
44
+ end
45
+ if spec then
46
+ if Gem::Specification.respond_to?(:find_by_name)
47
+ res = spec.lib_dirs_glob.split('/')
48
+ else
49
+ res = Gem.searcher.lib_dirs_for(spec).split('/')
50
+ end
51
+ res.pop
52
+ services_path = res.join('/').concat("/#{_file}")
53
+ return services_path if File::exist?(services_path)
54
+ return false
55
+ else
56
+ return false
57
+ end
58
+ end
59
+
60
+
61
+
20
62
  # facilité pour vérifier si le process actif est root
21
63
  # @return [Bool] vrai ou faux
22
64
  def is_root?
@@ -35,7 +77,7 @@ module Splash
35
77
  unless is_root?
36
78
  return {:case => :not_root, :more => "subcommands : #{method.to_s}"}
37
79
  else
38
- return self.send method
80
+ return self.send method, options
39
81
  end
40
82
  end
41
83
 
@@ -47,7 +89,7 @@ module Splash
47
89
  # @option options [String] :daemon_group the group to change privileges
48
90
  # @option options [String] :stderr_trace the path of the file where to redirect STDERR
49
91
  # @option options [String] :stdout_trace the path of the file where to redirect STDOUT
50
- # @option options [Bool] :debug option to run foreground
92
+ # @option options [Bool] :foreground option to run foreground
51
93
  # @yield a process definion or block given
52
94
  # @example usage inline
53
95
  # class Test
@@ -86,11 +128,11 @@ module Splash
86
128
  def daemonize(options)
87
129
  #Process.euid = 0
88
130
  #Process.egid = 0
89
- return yield if options[:debug]
131
+
90
132
  trap("SIGINT"){ exit! 0 }
91
133
  trap("SIGTERM"){ exit! 0 }
92
134
  trap("SIGHUP"){ exit! 0 }
93
-
135
+ return yield if options[:foreground]
94
136
  fork do
95
137
  #Process.daemon
96
138
  File.open(options[:pid_file],"w"){|f| f.puts Process.pid } if options[:pid_file]
@@ -1,54 +1,31 @@
1
1
  # coding: utf-8
2
+ Dir[File.dirname(__FILE__) + '/orchestrator/*.rb'].each {|file| require file }
3
+
2
4
  module Splash
3
5
  module Orchestrator
4
6
 
5
- module SchedulerHooks
6
- def on_pre_trigger(job, trigger_time)
7
-
8
- end
9
-
10
- def on_post_trigger(job, trigger_time)
11
-
12
- end
13
-
14
- def init_log
15
-
16
- end
17
- end
18
-
19
- module Commander
20
- include Splash::Transports
21
- def send_message (options)
22
- client = get_default_client
23
- client.publish options
24
- end
25
- end
26
-
27
- module Grammar
28
-
29
- VERBS=[:ping]
30
-
31
- def ping(payload)
32
- return "Pong : #{payload[:hostname]} !"
33
- end
34
- end
35
-
36
7
  class Scheduler
37
8
  include Splash::Constants
38
9
  include Splash::Helpers
39
10
  include Splash::Config
40
11
  include Splash::Transports
41
12
  include Splash::Orchestrator::Grammar
42
- def initialize
13
+ def initialize(options = {})
14
+ $stdout.sync = true
15
+ $stderr.sync = true
43
16
  @server = Rufus::Scheduler::new
44
17
  @server.extend SchedulerHooks
45
- @server.init_log
46
18
  @config = get_config
47
19
  @result = LogScanner::new
20
+ puts "Splash Orchestrator starting :"
21
+ if options[:scheduling] then
22
+ puts " * Initializing commands Scheduling."
23
+ self.init_commands_scheduling
24
+ end
48
25
  sched,value = @config.daemon_logmon_scheduling.flatten
26
+ puts " * Initializing logs monitorings & notifications."
49
27
  @server.send sched,value do
50
28
  begin
51
- puts "Notify"
52
29
  @result.analyse
53
30
  @result.notify
54
31
  $stdout.flush
@@ -58,12 +35,21 @@ module Splash
58
35
  end
59
36
  hostname = Socket.gethostname
60
37
  transport = get_default_subscriber queue: "splash.#{hostname}.input"
38
+ if transport.class == Hash and transport.include? :case then
39
+ splash_exit transport
40
+ end
61
41
  transport.subscribe(:block => true) do |delivery_info, properties, body|
62
42
  content = YAML::load(body)
63
43
  if VERBS.include? content[:verb]
64
- res = self.send content[:verb], content[:payload]
44
+ puts "Receive valid remote order, verb : #{content[:verb].to_s}"
45
+ if content[:payload] then
46
+ res = self.send content[:verb], content[:payload]
47
+ else
48
+ res = self.send content[:verb]
49
+ end
65
50
  get_default_client.publish queue: content[:return_to], message: res.to_yaml
66
51
  else
52
+ puts "Receive INVALID remote order, verb : #{content[:verb].to_s}"
67
53
  get_default_client.publish queue: content[:return_to], message: "Unkown verb #{content[:verb]}".to_yaml
68
54
  end
69
55
  end
@@ -72,6 +58,29 @@ module Splash
72
58
  def terminate
73
59
  end
74
60
 
61
+ private
62
+ def init_commands_scheduling
63
+ config = get_config.commands
64
+ commands = config.select{|key,value| value.include? :schedule}.keys
65
+ commands.each do |command|
66
+ sched,value = config[command][:schedule].flatten
67
+ puts " => Scheduling command #{command.to_s}"
68
+ @server.send sched,value do
69
+ self.execute command: command.to_s
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+ def execute(options)
76
+ command = Splash::CommandWrapper::new(options[:command])
77
+ if options[:ack] then
78
+ command.ack
79
+ else
80
+ command.call_and_notify trace: true, notify: true, callback: true
81
+ end
82
+ end
83
+
75
84
  end
76
85
 
77
86
 
@@ -0,0 +1,43 @@
1
+ # coding: utf-8
2
+ module Splash
3
+ module Orchestrator
4
+ module Grammar
5
+
6
+ include Splash::Config
7
+ VERBS=[:ping,:list_commands,:execute_command,:ack_command]
8
+
9
+ def ping(payload)
10
+ return "Pong : #{payload[:hostname]} !"
11
+ end
12
+
13
+
14
+ def list_commands
15
+ return get_config.commands
16
+ end
17
+
18
+ def ack_command
19
+ return self.execute command: payload[:name], ack: true
20
+ end
21
+
22
+
23
+ def execute_command(payload)
24
+ unless get_config.commands.include? payload[:name].to_sym
25
+ puts " * Command not found"
26
+ return { :case => :not_found }
27
+ end
28
+ if payload.include? :schedule then
29
+ sched,value = payload[:schedule].flatten
30
+ else
31
+ sched = :in
32
+ value = '1s'
33
+ end
34
+ puts " * Schedule remote call command #{payload[:name]}, scheduling : #{sched.to_s} #{value}"
35
+ @server.send sched,value do
36
+ self.execute command: payload[:name]
37
+ end
38
+ return { :case => :quiet_exit }
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,16 @@
1
+ # coding: utf-8
2
+ module Splash
3
+ module Orchestrator
4
+
5
+ module SchedulerHooks
6
+ def on_pre_trigger(job, trigger_time)
7
+
8
+ end
9
+
10
+ def on_post_trigger(job, trigger_time)
11
+
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -1,19 +1,42 @@
1
1
  # coding: utf-8
2
- Dir[File.dirname(__FILE__) + '/transports/*.rb'].each {|file| require file }
3
2
 
4
3
  module Splash
5
4
  module Transports
6
5
  include Splash::Config
7
6
 
8
- def get_default_subscriber(queue)
9
- aclass = "Splash::Transports::#{get_config[:transports][:active].to_s.capitalize}::Subscriber"
10
- return Kernel.const_get(aclass)::new(queue)
7
+ def get_default_subscriber(options)
8
+ config = get_config.transports
9
+ transport = config[:active]
10
+ host = config[transport][:host]
11
+ port = config[transport][:port]
12
+ unless verify_service host: host, port: port then
13
+ return { :case => :service_dependence_missing, :more => "RabbitMQ Transport not available." }
14
+ end
15
+ aclass = "Splash::Transports::#{transport.capitalize}::Subscriber"
16
+ begin
17
+ return Kernel.const_get(aclass)::new(options)
18
+ rescue
19
+ return { :case => :configuration_error, :more => "Transport specified for queue #{options[:queue]} inexistant : #{transport}"}
20
+ end
11
21
  end
12
22
 
13
23
  def get_default_client
14
- aclass = "Splash::Transports::#{get_config[:transports][:active].to_s.capitalize}::Client"
15
- return Kernel.const_get(aclass)::new
24
+ config = get_config.transports
25
+ transport = config[:active]
26
+ host = config[transport][:host]
27
+ port = config[transport][:port]
28
+ unless verify_service host: host, port: port then
29
+ return { :case => :service_dependence_missing, :more => "RabbitMQ Transport not available." }
30
+ end
31
+ aclass = "Splash::Transports::#{transport.to_s.capitalize}::Client"
32
+ begin
33
+ return Kernel.const_get(aclass)::new
34
+ rescue
35
+ return { :case => :configuration_error, :more => "Transport specified inexistant : #{transport}"}
36
+ end
16
37
  end
17
38
 
18
39
  end
19
40
  end
41
+
42
+ Dir[File.dirname(__FILE__) + '/transports/*.rb'].each {|file| require file }
@@ -11,26 +11,46 @@ module Splash
11
11
 
12
12
  def initialize(options = {})
13
13
  @config = get_config.transports
14
- @connection = Bunny.new url: @config[:rabbitmq][:url]
15
- @connection.start
16
- @channel = @connection.create_channel
17
- @queue = @channel.queue options[:queue]
18
-
14
+ host = @config[:rabbitmq][:host]
15
+ port = @config[:rabbitmq][:port]
16
+ @url = "amqp://#{host}:#{port}"
17
+ begin
18
+ @connection = Bunny.new url: @url
19
+ @connection.start
20
+ @channel = @connection.create_channel
21
+ @queue = @channel.queue options[:queue]
22
+ rescue Bunny::Exception
23
+ return { :case => :service_dependence_missing, :more => "RabbitMQ Transport not available." }
24
+ end
19
25
  end
20
26
 
27
+
21
28
  end
22
29
 
23
30
 
24
31
  class Client
25
32
  include Splash::Config
33
+ include Splash::Transports
34
+
26
35
  def initialize
27
36
  @config = get_config.transports
28
- @connection = Bunny.new url: @config[:rabbitmq][:url]
29
- @connection.start
30
- @channel = @connection.create_channel
37
+ host = @config[:rabbitmq][:host]
38
+ port = @config[:rabbitmq][:port]
39
+ @url = "amqp://#{host}:#{port}"
40
+ begin
41
+ @connection = Bunny.new url: @url
42
+ @connection.start
43
+ @channel = @connection.create_channel
44
+ rescue Bunny::Exception
45
+ return { :case => :service_dependence_missing, :more => "RabbitMQ Transport not available." }
46
+ end
31
47
  end
32
48
 
33
49
 
50
+ def purge(options)
51
+ @channel.queue(options[:queue]).purge
52
+ end
53
+
34
54
  def publish(options ={})
35
55
  return @channel.default_exchange.publish(options[:message], :routing_key => options[:queue])
36
56
  end
@@ -39,6 +59,19 @@ module Splash
39
59
  return @channel.acknowledge(ack, false)
40
60
  end
41
61
 
62
+ def execute(order)
63
+ queue = order[:return_to]
64
+ lock = Mutex.new
65
+ res = nil
66
+ condition = ConditionVariable.new
67
+ get_default_subscriber(queue: queue).subscribe(timeout: 5) do |delivery_info, properties, payload|
68
+ res = YAML::load(payload)
69
+ lock.synchronize { condition.signal }
70
+ end
71
+ get_default_client.publish queue: order[:queue], message: order.to_yaml
72
+ lock.synchronize { condition.wait(lock) }
73
+ return res
74
+ end
42
75
 
43
76
  def get(options ={})
44
77
  queue = @channel.queue(options[:queue])
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.1.1
4
+ version: 0.2.0
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-10 00:00:00.000000000 Z
11
+ date: 2020-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -236,6 +236,8 @@ files:
236
236
  - lib/splash/cli/logs.rb
237
237
  - lib/splash/commands.rb
238
238
  - lib/splash/config.rb
239
+ - lib/splash/config/sanitycheck.rb
240
+ - lib/splash/config/setup.rb
239
241
  - lib/splash/constants.rb
240
242
  - lib/splash/controller.rb
241
243
  - lib/splash/dependencies.rb
@@ -243,6 +245,8 @@ files:
243
245
  - lib/splash/helpers.rb
244
246
  - lib/splash/logs.rb
245
247
  - lib/splash/orchestrator.rb
248
+ - lib/splash/orchestrator/grammar.rb
249
+ - lib/splash/orchestrator/hooks.rb
246
250
  - lib/splash/templates.rb
247
251
  - lib/splash/transports.rb
248
252
  - lib/splash/transports/rabbitmq.rb