prometheus-splash 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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