elesai 0.9.3 → 0.10.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -10,6 +10,7 @@ where:
10
10
 
11
11
  * `<action>` is one of `show` or `check`
12
12
  * `<component>` (for `show` action) is one of
13
+ * `adapter`
13
14
  * `virtualdrive` (or `vd`)
14
15
  * `physicaldrive` (or `pd`)
15
16
  * `bbu`
@@ -18,6 +19,7 @@ Global options include:
18
19
 
19
20
  * `-d`, `--debug`: enable *debug* mode
20
21
  * `-f`, `--fake DIRECTORY`: specifies path to directory containing output of MegaCli invocations:
22
+ * `adpallinfo_aall`: output from `MegaCli -adpallinfo -aall -nolog`
21
23
  * `ldlist_aall`: output from `MegaCli -pdlist -aall -nolog`
22
24
  * `ldpdinfo_aall`: output from `MegaCli -ldpdinfo -aall -nolog`
23
25
  * `adpbbucmd_aall`: output from `MegaCli -adpcbucmd -aall -nolog`
@@ -0,0 +1,146 @@
1
+ require 'senedsa'
2
+
3
+ module Elesai; module Action
4
+
5
+ class Check
6
+
7
+ DEFAULT_SENEDSA_CONFIG_FILE = File.join(ENV['HOME'],"/.senedsa/config")
8
+
9
+ include Senedsa
10
+
11
+ def initialize(arguments,options)
12
+ @options = options.merge!({ :monitor => :nagios, :mode => :active })
13
+ @arguments = []
14
+ @lsi = nil
15
+
16
+ opts = OptionParser.new
17
+ opts.banner = "Usage: #{ID} [options] check [check_options]"
18
+ opts.separator ""
19
+ opts.separator "Check Options"
20
+ opts.on('-M', '--monitor [nagios]', [:nagios], "Monitoring system") { |o| @options[:monitor] = o }
21
+ opts.on('-m', '--mode [active|passive]', [:active, :passive], "Monitoring mode") { |o| @options[:mode] = o }
22
+ opts.on('-H', '--nsca_hostname HOSTNAME', String, "NSCA hostname to send passive checks") { |o| @options[:nsca_hostame] = o }
23
+ opts.on('-c', '--config CONFIG', String, "Path to Senedsa (send_nsca) configuration" ) { |o| @options[:senedsa_config] = o }
24
+ opts.on('-S', '--svc_descr SVC_DESR', String, "Nagios service description") { |o| @options[:svc_descr] = o }
25
+ opts.order!(arguments)
26
+
27
+ options_valid?
28
+ end
29
+
30
+ def exec
31
+
32
+ @lsi = LSI.new(:megacli => @options[:megacli], :fake => @options[:fake])
33
+
34
+ plugin_output = ""
35
+ plugin_status = ""
36
+
37
+ @lsi.physicaldrives.each do |id,physicaldrive|
38
+ drive_plugin_string = "[PD:#{physicaldrive._id}:#{physicaldrive[:size]}:#{physicaldrive[:mediatype]}:#{physicaldrive[:pdtype]}]"
39
+ unless physicaldrive[:firmwarestate].state == :online or physicaldrive[:firmwarestate].state == :hotspare
40
+ plugin_output += " #{drive_plugin_string}:#{physicaldrive[:firmwarestate].state}"
41
+ plugin_status = :critical if physicaldrive[:firmwarestate] == :failed
42
+ plugin_status = :warning if plugin_status.empty?
43
+ end
44
+ unless physicaldrive[:mediaerrorcount].to_i < 10
45
+ plugin_output += " #{drive_plugin_string}:MediaError:#{physicaldrive[:mediaerrorcount]}"
46
+ plugin_status = :warning if plugin_status.empty?
47
+ end
48
+ unless physicaldrive[:predictivefailurecount].to_i < 5
49
+ plugin_output += " #{drive_plugin_string}:PredictiveFailure:#{physicaldrive[:predictivefailurecount]}"
50
+ plugin_status = :warning if plugin_status.empty?
51
+ end
52
+ end
53
+
54
+ @lsi.virtualdrives.each do |vd|
55
+ vd_plugin_string = "[VD:#{vd._id}]"
56
+ unless vd[:state] == :optimal
57
+ plugin_output += " #{vd_plugin_string}:#{vd[:state]}"
58
+ plugin_status = :critical
59
+ end
60
+ end
61
+
62
+ @lsi.bbus.each do |bbu|
63
+
64
+ [:temperature, :learncyclestatus].each do |attr|
65
+ unless bbu[:firmwarestatus][attr] == 'OK'
66
+ plugin_output += " [BBU:#{bbu._id}:#{attr}:#{bbu[:firmwarestatus][attr]}]"
67
+ plugin_status = :warning if plugin_status == ""
68
+ end
69
+ end
70
+
71
+ [:batterypackmissing, :batteryreplacementrequired].each do |attr|
72
+ unless bbu[:firmwarestatus][attr] == 'No'
73
+ plugin_output += " [BBU:#{attr}:#{bbu[:firmwarestatus][attr]}]"
74
+ plugin_status = :warning if plugin_status == ""
75
+ end
76
+ end
77
+
78
+ if bbu[:batterytype] == 'iBBU'
79
+ if bbu[:firmwarestatus][:learncycleactive] == 'Yes'
80
+ plugin_output += " learn cycle enabled: [BBU:absolutestateofcharge:#{bbu[:gasgaugestatus][:absolutestateofcharge]}]"
81
+ else
82
+ unless bbu[:firmwarestatus][:voltage] == 'OK'
83
+ plugin_output += " [BBU:#{bbu._id}:#{attr}:#{bbu[:firmwarestatus][attr]}]"
84
+ plugin_status = :warning if plugin_status == ""
85
+ end
86
+ if bbu[:firmwarestatus][:chargingstatus] == 'None' or bbu[:gasgaugestatus][:discharging] == 'No'
87
+ if bbu[:gasgaugestatus][:absolutestateofcharge].number <= 65
88
+ plugin_output += " [BBU:absolutestateofcharge:#{bbu[:gasgaugestatus][:absolutestateofcharge]}]"
89
+ plugin_status = :warning if plugin_status == ""
90
+ end
91
+ if bbu[:capacityinfo][:remainingcapacity].number <= bbu[:capacityinfo][:remainingcapacityalarm].number
92
+ plugin_output += " [BBU:remainingcapacity:#{bbu[:capacityinfo][:remainingcapacityalarm]}]"
93
+ plugin_status = :warning if plugin_status == ""
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ if plugin_output.empty? and plugin_status.empty?
101
+ @lsi.adapters.each do |adapter|
102
+ plugin_output += " [#{adapter._id}: #{adapter[:versions][:productname].gsub(/\s+/,'_')} OK]"
103
+ end
104
+ end
105
+ plugin_status = :ok if plugin_status.empty?
106
+
107
+ case @options[:monitor]
108
+ when :nagios
109
+ case @options[:mode]
110
+ when :active
111
+ puts "#{plugin_status.to_s.upcase}:#{plugin_output}"
112
+ exit SendNsca::STATUS[plugin_status]
113
+ when :passive
114
+ sn = SendNsca.new @options
115
+ begin
116
+ sn.send plugin_status , plugin_output
117
+ rescue SendNsca::SendNscaError => e
118
+ raise RuntimeError, "send_nsca failed: #{e.message}"
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+
125
+ protected
126
+
127
+ def options_valid?
128
+ raise OptionParser::MissingArgument, "NSCA hostname (-H) must be specified" if @options[:nsca_hostname].nil? and @options[:mode] == 'passive'
129
+ raise OptionParser::MissingArgument, "service description (-S) must be specified" if @options[:svc_descr].nil? and @options[:mode] == 'passive'
130
+ end
131
+
132
+ def config_options?
133
+ cfg_file = nil
134
+ cfg_file = @options[:senedsa_config] unless @options[:senedsa_config].nil?
135
+ cfg_file = DEFAULT_SENEDSA_CONFIG_FILE if @options[:senedsa_config].nil? and File.readable? DEFAULT_SENEDSA_CONFIG_FILE
136
+
137
+ unless cfg_file.nil?
138
+ @options.merge!(Senedsa::SendNsca.configure(cfg_file))
139
+ @options[:senedsa_config] = cfg_file
140
+ end
141
+ end
142
+
143
+
144
+ end
145
+
146
+ end end
@@ -0,0 +1,83 @@
1
+ module Elesai; module Action
2
+
3
+ class Show
4
+
5
+ COMPONENTS = %w(adapter virtualdrive vd physicaldrive pd bbu)
6
+
7
+ def initialize(arguments,options)
8
+
9
+ @options = options
10
+ @arguments = arguments
11
+
12
+ @component = nil
13
+
14
+ opts = OptionParser.new
15
+ opts.banner = "Usage: #{ID} [options] show <component>"
16
+ opts.separator ""
17
+ opts.separator " <component> is physicaldisk|pd, virtualdisk|vd, bbu"
18
+ opts.order!(@arguments)
19
+
20
+ options_valid?
21
+ arguments_valid?
22
+ process_arguments
23
+
24
+ @show = { :adapter => self.method(:show_adapter),
25
+ :virtualdrive => self.method(:show_virtualdrive),
26
+ :physicaldrive => self.method(:show_physicaldrive),
27
+ :bbu => self.method(:show_bbu)
28
+ }
29
+ end
30
+
31
+ def exec
32
+ @lsi = LSI.new(:megacli => @options[:megacli], :fake => @options[:fake], :hint => @component)
33
+ @show[@component].call
34
+ end
35
+
36
+ protected
37
+
38
+ def options_valid?
39
+ true
40
+ end
41
+
42
+ def arguments_valid?
43
+ raise ArgumentError, "missing component" if @arguments.size == 0
44
+ raise ArgumentError, "too many components" if @arguments.size > 1
45
+ raise ArgumentError, "invalid component #{@arguments[0]}" unless COMPONENTS.include? @arguments[0]
46
+ true
47
+ end
48
+
49
+ def process_arguments
50
+ @component = case @arguments[0].to_sym
51
+ when :vd then :virtualdrive
52
+ when :pd then :physicaldrive
53
+ else @arguments[0].to_sym
54
+ end
55
+ end
56
+
57
+ def show_virtualdrive
58
+ @lsi.virtualdrives.each do |virtualdrive|
59
+ print "#{virtualdrive}\n"
60
+ end
61
+ end
62
+
63
+ def show_physicaldrive
64
+ @lsi.physicaldrives.each do |id,physicaldrive|
65
+ print "#{physicaldrive}\n"
66
+ end
67
+ end
68
+
69
+ def show_bbu
70
+ @lsi.bbus.each do |bbu|
71
+ print "#{bbu}\n"
72
+ end
73
+ end
74
+
75
+ def show_adapter
76
+ @lsi.adapters.each do |adapter|
77
+ print "#{adapter}\n"
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ end end
@@ -0,0 +1,5 @@
1
+ require 'elesai/action/show'
2
+ require 'elesai/action/check'
3
+
4
+ module Elesai; module Action
5
+ end end
data/lib/elesai/cli.rb CHANGED
@@ -1,26 +1,26 @@
1
1
  require 'optparse'
2
2
  require 'syslog'
3
3
  require 'io/wait'
4
- require 'senedsa'
5
- include Senedsa
4
+ require 'elesai'
5
+ require 'elesai/action'
6
6
  require 'elesai/version'
7
7
  require 'elesai/about'
8
8
 
9
+ include Elesai::Action
10
+
9
11
  module Elesai
10
12
 
11
13
  class CLI
12
14
 
13
15
  COMMANDS = %w(show check)
14
- COMPONENTS = %w(virtualdrive vd physicaldrive pd bbu)
15
- DEFAULT_CONFIG_FILE = File.join(ENV['HOME'],"/.senedsa/config")
16
16
 
17
17
  def initialize(arguments)
18
18
  @arguments = arguments
19
19
  @whoami = File.basename($PROGRAM_NAME).to_sym
20
20
 
21
- @global_options = { :debug => false, :megacli => 'MegaCli' }
22
- @action_options = { :monitor => :nagios, :mode => :active }
21
+ @options = { :debug => false, :megacli => 'MegaCli' }
23
22
  @action = nil
23
+ @elesai = nil
24
24
  end
25
25
 
26
26
  def run
@@ -28,9 +28,8 @@ module Elesai
28
28
  parsed_options?
29
29
 
30
30
  @log = Elesai::Logger.instance.log
31
- @log.level = Log4r::INFO unless @global_options[:debug]
31
+ @log.level = Log4r::INFO unless @options[:debug]
32
32
 
33
- config_options?
34
33
  arguments_valid?
35
34
  options_valid?
36
35
  process_options
@@ -38,8 +37,8 @@ module Elesai
38
37
  process_command
39
38
 
40
39
  rescue => e #ArgumentError, OptionParser::MissingArgument, Senedsa::SendNsca::ConfigurationError => e
41
- if @global_options[:debug]
42
- output_message "#{e.message}\n #{e.backtrace.join("\n ")}",1
40
+ if @options[:debug]
41
+ output_message "#{e.class}: #{e.message}\n #{e.backtrace.join("\n ")}",1
43
42
  else
44
43
  output_message e.message,1
45
44
  end
@@ -53,52 +52,26 @@ module Elesai
53
52
 
54
53
  opts.banner = "Usage: #{ID} [options] <action> [options]"
55
54
  opts.separator ""
56
- opts.separator "Actions:"
55
+ opts.separator "Actions: (<action> -h displays help for specific action)"
57
56
  opts.separator " show Displays component information"
58
57
  opts.separator " check Performs health checks"
59
58
  opts.separator ""
60
59
  opts.separator "General options:"
61
- opts.on('-m', '--megacli MEGACLI', String, "Path to MegaCli binary") { |megacli| @global_options[:megacli] = megacli }
62
- opts.on('-f', '--fake DIRECTORY', String, "Path to directory with Megacli output") { |dir| @global_options[:fake] = dir }
63
- opts.on('-d', '--debug', "Enable debug mode") { @global_options[:debug] = true}
60
+ opts.on('-m', '--megacli MEGACLI', String, "Path to MegaCli binary") { |megacli| @options[:megacli] = megacli }
61
+ opts.on('-f', '--fake DIRECTORY', String, "Path to directory with Megacli output") { |dir| @options[:fake] = dir }
62
+ opts.on('-d', '--debug', "Enable debug mode") { @options[:debug] = true}
64
63
  opts.on('-a', '--about', "Display #{ID} information") { output_message ABOUT, 0 }
65
64
  opts.on('-V', '--version', "Display #{ID} version") { output_message VERSION, 0 }
66
- opts.on_tail('--help', "Show this message") { @global_options[:HELP] = true }
67
-
68
- actions = {
69
- :show => OptionParser.new do |aopts|
70
- aopts.banner = "Usage: #{ID} [options] show <component>"
71
- aopts.separator ""
72
- aopts.separator " <component> is physicaldisk|pd, virtualdisk|vd, bbu"
73
- end,
74
- :check => OptionParser.new do |aopts|
75
- aopts.banner = "Usage: #{ID} [options] check [check_options]"
76
- aopts.separator ""
77
- aopts.separator "Check Options"
78
- aopts.on('-M', '--monitor [nagios]', [:nagios], "Monitoring system") { |monitor| @action_options[:monitor] = monitor }
79
- aopts.on('-m', '--mode [active|passive]', [:active, :passive], "Monitoring mode") { |mode| @action_options[:mode] = mode }
80
- aopts.on('-H', '--nsca_hostname HOSTNAME', String, "NSCA hostname to send passive checks") { |nsca_hostname| @action_options[:nsca_hostame] = nsca_hostname }
81
- aopts.on('-c', '--config CONFIG', String, "Path to Senedsa (send_nsca) configuration" ) { |config| @action_options[:senedsa_config] = config }
82
- aopts.on('-S', '--svc_descr SVC_DESR', String, "Nagios service description") { |svc_descr| @action_options[:svc_descr] = svc_descr }
83
- end
84
- }
85
-
86
- opts.order!
87
- output_message opts, 0 if (@arguments.size == 0 and @whoami != :check_lsi) or @global_options[:HELP]
88
-
89
- @action = @whoami == :check_lsi ? :check : @arguments.shift.to_sym
90
- raise OptionParser::InvalidArgument, "invalid action #@action" if actions[@action].nil?
91
- actions[@action].order!
92
- end
65
+ opts.on_tail('--help', "Show this message") { @options[:HELP] = true }
93
66
 
94
- def config_options?
95
- cfg_file = nil
96
- cfg_file = @action_options[:senedsa_config] unless @action_options[:senedsa_config].nil?
97
- cfg_file = DEFAULT_CONFIG_FILE if @action_options[:senedsa_config].nil? and File.readable? DEFAULT_CONFIG_FILE
67
+ opts.order!(@arguments)
68
+ output_message opts, 0 if (@arguments.size == 0 and @whoami != :check_lsi) or @options[:HELP]
98
69
 
99
- unless cfg_file.nil?
100
- @action_options.merge!(Senedsa::SendNsca.configure(cfg_file))
101
- @action_options[:senedsa_config] = cfg_file
70
+ @action = @whoami == :check_lsi ? :check : @arguments.shift.to_sym
71
+ case @action
72
+ when :show then @elesai = Show.new(@arguments,@options)
73
+ when :check then @elesai = Check.new(@arguments,@options)
74
+ else raise OptionParser::InvalidArgument, "invalid action #@action"
102
75
  end
103
76
  end
104
77
 
@@ -107,11 +80,7 @@ module Elesai
107
80
  end
108
81
 
109
82
  def options_valid?
110
- case @action
111
- when :check
112
- raise OptionParser::MissingArgument, "NSCA hostname (-H) must be specified" if @action_options[:nsca_hostname].nil? and @action_options[:mode] == 'passive'
113
- raise OptionParser::MissingArgument, "service description (-S) must be specified" if @action_options[:svc_descr].nil? and @action_options[:mode] == 'passive'
114
- end
83
+ true
115
84
  end
116
85
 
117
86
  def process_options
@@ -119,131 +88,16 @@ module Elesai
119
88
  end
120
89
 
121
90
  def process_arguments
122
- @action_options[:hint] = @arguments[0].nil? ? nil : @arguments[0].to_sym
123
91
  true
124
92
  end
125
93
 
126
94
  def process_command
127
-
128
- @lsi = LSIArray.new(:megacli => @global_options[:megacli], :fake => @global_options[:fake], :hint => @action_options[:hint])
129
-
130
- case @action
131
- when :show then run_show
132
- when :check then run_check
133
- end
134
-
135
- end
136
-
137
- def run_show
138
-
139
- raise ArgumentError, "missing component" if @arguments.size == 0
140
- component = @arguments[0]
141
-
142
- case component
143
- when 'virtualdrive', 'vd'
144
- @lsi.virtualdrives.each do |virtualdrive|
145
- print "#{virtualdrive}\n"
146
- end
147
- when 'physicaldrive', 'pd'
148
- @lsi.physicaldrives.each do |id,physicaldrive|
149
- print "#{physicaldrive}\n"
150
- end
151
- when 'bbu'
152
- @lsi.bbus.each do |bbu|
153
- print "#{bbu}\n"
154
- end
155
- else
156
- raise ArgumentError, "invalid component #{component}"
157
- end
158
- end
159
-
160
- def run_check
161
-
162
- plugin_output = ""
163
- plugin_status = ""
164
-
165
- @lsi.physicaldrives.each do |id,physicaldrive|
166
- drive_plugin_string = "[PD:#{physicaldrive._id}:#{physicaldrive[:size]}:#{physicaldrive[:mediatype]}:#{physicaldrive[:pdtype]}]"
167
- unless physicaldrive[:firmwarestate].state == :online or physicaldrive[:firmwarestate].state == :hotspare
168
- plugin_output += " #{drive_plugin_string}:#{physicaldrive[:firmwarestate].state}"
169
- plugin_status = :critical if physicaldrive[:firmwarestate] == :failed
170
- plugin_status = :warning if plugin_status.empty?
171
- end
172
- unless physicaldrive[:mediaerrorcount].to_i < 10
173
- plugin_output += " #{drive_plugin_string}:MediaError:#{physicaldrive[:mediaerrorcount]}"
174
- plugin_status = :warning if plugin_status.empty?
175
- end
176
- unless physicaldrive[:predictivefailurecount].to_i < 5
177
- plugin_output += " #{drive_plugin_string}:PredictiveFailure:#{physicaldrive[:predictivefailurecount]}"
178
- plugin_status = :warning if plugin_status.empty?
179
- end
180
- end
181
-
182
- @lsi.virtualdrives.each do |vd|
183
- vd_plugin_string = "[VD:#{vd._id}]"
184
- unless vd[:state] == :optimal
185
- plugin_output += " #{vd_plugin_string}:#{vd[:state]}"
186
- plugin_status = :critical
187
- end
188
- end
189
-
190
- @lsi.bbus.each do |bbu|
191
-
192
- [:voltage, :temperature, :learncyclestatus].each do |attr|
193
- unless bbu[:firmwarestatus][attr] == 'OK'
194
- plugin_output += " [BBU:#{bbu._id}:#{attr}:#{bbu[:firmwarestatus][attr]}]"
195
- plugin_status = :warning if plugin_status == ""
196
- end
197
- end
198
-
199
- [:batterypackmissing, :batteryreplacementrequired].each do |attr|
200
- unless bbu[:firmwarestatus][attr] == 'No'
201
- plugin_output += " [BBU:#{attr}:#{bbu[:firmwarestatus][attr]}]"
202
- plugin_status = :warning if plugin_status == ""
203
- end
204
- end
205
-
206
- if bbu[:batterytype] == 'iBBU'
207
- if bbu[:firmwarestatus][:learncycleactive] == 'Yes'
208
- plugin_output += " [BBU:absolutestateofcharge:#{bbu[:gasgaugestatus][:absolutestateofcharge]}]"
209
- else
210
- if bbu[:firmwarestatus][:chargingstatus] == 'None'
211
- if bbu[:gasgaugestatus][:absolutestateofcharge].number <= 65
212
- plugin_output += " [BBU:absolutestateofcharge:#{bbu[:gasgaugestatus][:absolutestateofcharge]}]"
213
- plugin_status = :warning if plugin_status == ""
214
- end
215
- if bbu[:capacityinfo][:remainingcapacity].number <= bbu[:capacityinfo][:remainingcapacityalarm].number
216
- plugin_output += " [BBU:remainingcapacity:#{bbu[:capacityinfo][:remainingcapacityalarm]}]"
217
- plugin_status = :warning if plugin_status == ""
218
- end
219
- end
220
- end
221
- end
222
- end
223
-
224
- plugin_output = " no LSI RAID errors found" if plugin_output.empty? and plugin_status.empty?
225
- plugin_status = :ok if plugin_status.empty?
226
-
227
- case @action_options[:monitor]
228
- when :nagios
229
- case @action_options[:mode]
230
- when :active
231
- puts "#{plugin_status.to_s.upcase}:#{plugin_output}"
232
- exit SendNsca::STATUS[plugin_status]
233
- when :passive
234
- sn = SendNsca.new @action_options
235
- begin
236
- sn.send plugin_status , plugin_output
237
- rescue SendNsca::SendNscaError => e
238
- output_message "send_nsca failed: #{e.message}", 1
239
- end
240
- end
241
- end
95
+ @elesai.exec
242
96
  end
243
97
 
244
98
  def output_message(message, exitstatus=nil)
245
99
  m = (! exitstatus.nil? and exitstatus > 0) ? "%s: error: %s" % [ID, message] : message
246
- Syslog.open("elesai", Syslog::LOG_PID | Syslog::LOG_CONS) { |s| s.err "error: #{message}" } unless @global_options[:debug]
100
+ Syslog.open("elesai", Syslog::LOG_PID | Syslog::LOG_CONS) { |s| s.err "error: #{message}" } unless @options[:debug]
247
101
  $stderr.write "#{m}\n" if STDIN.tty?
248
102
  exit exitstatus unless exitstatus.nil?
249
103
  end