elesai 0.9.3 → 0.10.5

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.
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