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 +2 -0
- data/lib/elesai/action/check.rb +146 -0
- data/lib/elesai/action/show.rb +83 -0
- data/lib/elesai/action.rb +5 -0
- data/lib/elesai/cli.rb +24 -170
- data/lib/elesai/lsi.rb +62 -84
- data/lib/elesai/megacli/_adpallinfo_aall.rb +102 -0
- data/lib/elesai/megacli/_adpbbucmd_aall.rb +107 -0
- data/lib/elesai/megacli/_ldpdinfo_aall.rb +140 -0
- data/lib/elesai/megacli/_pdlist_aall.rb +120 -0
- data/lib/elesai/megacli/megacli.rb +241 -0
- data/lib/elesai/megacli.rb +7 -643
- data/lib/elesai/version.rb +1 -1
- data/lib/elesai.rb +0 -1
- metadata +10 -2
@@ -0,0 +1,120 @@
|
|
1
|
+
module Elesai; module Megacli
|
2
|
+
|
3
|
+
class PDlist_aAll < Megacli
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@megacli = { :adapter => { :re => /^Adapter\s+#*(?<value>\d+)/, :method => self.method(:adapter_match) },
|
7
|
+
:physicaldrive => { :re => /^(?<key>Enclosure\s+Device\s+ID):\s+(?<value>\d+)/, :method => self.method(:physicaldrive_match) },
|
8
|
+
:exit => { :re => /^Exit Code: /, :method => self.method(:exit_match) },
|
9
|
+
:attribute => { :re => /^(?<key>[A-Za-z0-9()\s#'-.&]+)[:|=](?<value>.*)/, :method => self.method(:attribute_match) }
|
10
|
+
}.freeze
|
11
|
+
@command_arguments = "-pdlist -aall".freeze
|
12
|
+
@command_output_file = "pdlist_aall".freeze
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse!(lsi,opts)
|
16
|
+
fake = opts[:fake].nil? ? @command_arguments : File.join(opts[:fake],@command_output_file)
|
17
|
+
super lsi, :fake => fake, :megacli => opts[:megacli]
|
18
|
+
end
|
19
|
+
|
20
|
+
# State Machine
|
21
|
+
|
22
|
+
workflow do
|
23
|
+
|
24
|
+
state :start do
|
25
|
+
event :adapter_line, :transitions_to => :adapter
|
26
|
+
event :exit_line, :transitions_to => :exit
|
27
|
+
end
|
28
|
+
|
29
|
+
state :adapter do
|
30
|
+
event :adapter_line, :transitions_to => :adapter # empty adapter
|
31
|
+
event :physicaldrive_line, :transitions_to => :physicaldrive
|
32
|
+
event :exit_line, :transitions_to => :exit
|
33
|
+
end
|
34
|
+
|
35
|
+
state :physicaldrive do
|
36
|
+
event :attribute_line, :transitions_to => :physicaldrive
|
37
|
+
event :exit_line, :transitions_to => :exit
|
38
|
+
event :adapter_line, :transitions_to => :adapter
|
39
|
+
event :physicaldrive_line, :transitions_to => :physicaldrive
|
40
|
+
event :attribute_line, :transitions_to => :attribute
|
41
|
+
end
|
42
|
+
|
43
|
+
state :attribute do
|
44
|
+
event :attribute_line, :transitions_to => :attribute
|
45
|
+
event :physicaldrive_line, :transitions_to => :physicaldrive
|
46
|
+
event :adapter_line, :transitions_to => :adapter
|
47
|
+
event :exit_line, :transitions_to => :exit
|
48
|
+
end
|
49
|
+
|
50
|
+
state :exit
|
51
|
+
|
52
|
+
on_transition do |from, to, triggering_event, *event_args|
|
53
|
+
#puts self.spec.states[to].class
|
54
|
+
# puts " transition: #{from} >> #{triggering_event}! >> #{to}: #{event_args.join(' ')}"
|
55
|
+
#puts " #{current_state.meta}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
### Match Handlers
|
60
|
+
|
61
|
+
def virtualdrive_match(k,match)
|
62
|
+
@log.debug "VIRTUALDRIVE! #{match.string}"
|
63
|
+
key = match[:key].gsub(/\s+/,"").downcase
|
64
|
+
value = match[:value]
|
65
|
+
virtualdrive_line!(LSI::VirtualDrive.new,key,value)
|
66
|
+
end
|
67
|
+
|
68
|
+
def physicaldrive_match(k,match)
|
69
|
+
@log.debug "PHYSICALDRIVE! #{match.string}"
|
70
|
+
key = match[:key].gsub(/\s+/,"").downcase
|
71
|
+
value = match[:value]
|
72
|
+
physicaldrive_line!(LSI::PhysicalDrive.new,key,value)
|
73
|
+
end
|
74
|
+
|
75
|
+
### Line Handlers
|
76
|
+
|
77
|
+
# Virtual Drives
|
78
|
+
|
79
|
+
def virtualdrive_line(virtualdrive,key,value)
|
80
|
+
@log.debug " [#{current_state}] event: virtualdrive_line: new #{virtualdrive.inspect}"
|
81
|
+
virtualdrive[key.to_sym] = value.to_i
|
82
|
+
end
|
83
|
+
|
84
|
+
def on_virtualdrive_entry(old_state, event, *args)
|
85
|
+
@log.debug " [#{current_state}] on_entry: leaving #{old_state}; args: #{args}"
|
86
|
+
|
87
|
+
unless @context.current.nil?
|
88
|
+
if Elesai::LSI::VirtualDrive === @context.current
|
89
|
+
@context.close
|
90
|
+
end
|
91
|
+
end
|
92
|
+
virtualdrive = args[0]
|
93
|
+
@context.open virtualdrive
|
94
|
+
end
|
95
|
+
|
96
|
+
def on_virtualdrive_exit(new_state, event, *args)
|
97
|
+
@log.debug " [#{current_state}] on_exit: entering #{new_state}; args: #{args}"
|
98
|
+
@context.flash!(new_state)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Physical Drives
|
102
|
+
|
103
|
+
def physicaldrive_line(physicaldrive,key,value)
|
104
|
+
@log.debug " [#{current_state}] event: physicaldrive_line: new #{physicaldrive.inspect}"
|
105
|
+
physicaldrive[key.to_sym] = value.to_i
|
106
|
+
end
|
107
|
+
|
108
|
+
def on_physicaldrive_entry(old_state, event, *args)
|
109
|
+
@log.debug " [#{current_state}] on_entry: leaving #{old_state}; args: #{args}"
|
110
|
+
@context.open args[0]
|
111
|
+
end
|
112
|
+
|
113
|
+
def on_physicaldrive_exit(new_state, event, *args)
|
114
|
+
@log.debug " [#{current_state}] on_exit: entering #{new_state}; args: #{args}"
|
115
|
+
@context.flash!(new_state)
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
require 'workflow'
|
2
|
+
require 'open3'
|
3
|
+
require 'io/wait'
|
4
|
+
|
5
|
+
module Elesai; module Megacli
|
6
|
+
|
7
|
+
class Megacli
|
8
|
+
|
9
|
+
include Workflow
|
10
|
+
|
11
|
+
### Context
|
12
|
+
|
13
|
+
class Context
|
14
|
+
|
15
|
+
def initialize(current_state,lsi)
|
16
|
+
current_state.meta[:context] = { :stack => [] }
|
17
|
+
@context = current_state.meta[:context]
|
18
|
+
@lsi = lsi
|
19
|
+
@log = Elesai::Logger.instance.log
|
20
|
+
end
|
21
|
+
|
22
|
+
def open(component)
|
23
|
+
@log.debug " * Open #{component.inspect}"
|
24
|
+
@context[:stack].push(component)
|
25
|
+
@context[component.class] = component
|
26
|
+
@log.debug " + context: #{@context[:stack]}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def flash!(new_state)
|
30
|
+
new_state.meta[:context] = @context
|
31
|
+
@context = nil
|
32
|
+
@context = new_state.meta[:context]
|
33
|
+
@log.debug " + Flash context: #{@context[:stack]}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def close
|
37
|
+
component = @context[:stack].pop
|
38
|
+
@context[component.class] = nil
|
39
|
+
@log.debug " * Close #{component.inspect}"
|
40
|
+
case component
|
41
|
+
when Elesai::LSI::PhysicalDrive
|
42
|
+
pd = @lsi.add(component)
|
43
|
+
pd.add_adapter(adapter)
|
44
|
+
pd.add_virtualdrive(virtualdrive) unless virtualdrive.nil?
|
45
|
+
adapter.add_physicaldrive(pd)
|
46
|
+
when Elesai::LSI::VirtualDrive
|
47
|
+
vd = @lsi.add(component)
|
48
|
+
when Elesai::LSI::BBU
|
49
|
+
@lsi.add(component)
|
50
|
+
end
|
51
|
+
@log.debug " + context: #{@context[:stack]}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def current
|
55
|
+
@context[:stack][-1]
|
56
|
+
end
|
57
|
+
|
58
|
+
def adapter
|
59
|
+
@context[Elesai::LSI::Adapter]
|
60
|
+
end
|
61
|
+
|
62
|
+
def virtualdrive
|
63
|
+
@context[Elesai::LSI::VirtualDrive]
|
64
|
+
end
|
65
|
+
|
66
|
+
def physicaldrive
|
67
|
+
@context[Elesai::LSI::PhysicalDrive]
|
68
|
+
end
|
69
|
+
|
70
|
+
def bbu
|
71
|
+
@context[Elesai::LSI::BBU]
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
### Regular Expression Handlers
|
77
|
+
|
78
|
+
# Adapter
|
79
|
+
|
80
|
+
def adapter_match(k,match)
|
81
|
+
@log.debug "ADAPTER! #{match.string}"
|
82
|
+
key = 'id'
|
83
|
+
value = match[:value]
|
84
|
+
adapter_line!(LSI::Adapter.new,key,value)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Attribute
|
88
|
+
|
89
|
+
def attribute_match(k,match)
|
90
|
+
@log.debug "ATTRIBUTE! #{match.string}"
|
91
|
+
key = match[:key].gsub(/\s+/,"").downcase
|
92
|
+
value_tmp = match[:value]
|
93
|
+
value = value_tmp.nil? ? nil : value_tmp.strip
|
94
|
+
attribute_line!(key,value)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Exit
|
98
|
+
|
99
|
+
def exit_match(k,match)
|
100
|
+
@log.debug "EXIT! #{match.string}"
|
101
|
+
exit_line!
|
102
|
+
end
|
103
|
+
|
104
|
+
### State Machine Handlers
|
105
|
+
|
106
|
+
# Start
|
107
|
+
|
108
|
+
def on_start_exit(new_state, event, *args)
|
109
|
+
@log.debug " [#{current_state}]: on_exit : #{event} -> #{new_state}; args: #{args}"
|
110
|
+
@context = Context.new(current_state,@lsi)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Adapter
|
114
|
+
|
115
|
+
def adapter_line(adapter,key,value)
|
116
|
+
@log.debug " [#{current_state}] event adapter_line: new #{adapter.inspect}"
|
117
|
+
adapter[key.to_sym] = value.to_i
|
118
|
+
@lsi.add(adapter)
|
119
|
+
end
|
120
|
+
|
121
|
+
def on_adapter_entry(old_state, event, *args)
|
122
|
+
@log.debug " [#{current_state}] on_entry: leaving #{old_state}; args: #{args}"
|
123
|
+
|
124
|
+
@context.close unless @context.current.nil? or Elesai::LSI::Adapter === @context.current
|
125
|
+
@context.open args[0]
|
126
|
+
end
|
127
|
+
|
128
|
+
def on_adapter_exit(new_state, event, *args)
|
129
|
+
@log.debug " [#{current_state}] on_exit: entering #{new_state}; args: #{args}"
|
130
|
+
@context.flash!(new_state)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Attribute
|
134
|
+
|
135
|
+
def attribute_line(key,value)
|
136
|
+
@log.debug " [#{current_state}] event: attribute_line: #{key} => #{value}"
|
137
|
+
end
|
138
|
+
|
139
|
+
def on_attribute_entry(old_state, event, *args)
|
140
|
+
@log.debug " [#{current_state}] entry: leaving #{old_state}; args: #{args}; context: #{@context.current.class}"
|
141
|
+
|
142
|
+
c = @context.current
|
143
|
+
k = args[0].to_sym
|
144
|
+
v = args[1]
|
145
|
+
|
146
|
+
# Some attributes require special treatment for our purposes
|
147
|
+
|
148
|
+
case k
|
149
|
+
when :coercedsize, :noncoercedsize, :rawsize, :size
|
150
|
+
m = /(?<number>[0-9\.]+)\s+(?<unit>[A-Z]+)/.match(v)
|
151
|
+
v = LSI::PhysicalDrive::Size.new(m[:number],m[:unit])
|
152
|
+
when :raidlevel
|
153
|
+
m = /Primary-(?<primary>\d+),\s+Secondary-(?<secondary>\d+)/.match(v)
|
154
|
+
v = LSI::VirtualDrive::RaidLevel.new(m[:primary],m[:secondary])
|
155
|
+
when :firmwarestate
|
156
|
+
st,sp = v.gsub(/\s/,'').split(/,/)
|
157
|
+
state = st.gsub(/\s/,'_').downcase.to_sym
|
158
|
+
spin = sp.gsub(/\s/,'_').downcase.to_sym unless sp.nil?
|
159
|
+
v = LSI::PhysicalDrive::FirmwareState.new(state,spin)
|
160
|
+
when :state
|
161
|
+
v = v.gsub(/\s/,'_').downcase.to_sym
|
162
|
+
when :mediatype
|
163
|
+
v = v.scan(/[A-Z]/).join
|
164
|
+
when :inquirydata
|
165
|
+
v = v.gsub(/\s+/,' ')
|
166
|
+
when :relativedtateofcharge, :absolutestateofcharge, :remainingcapacityalarm, :remainingcapacity
|
167
|
+
m = /(?<number>[0-9\.]+)\s+(?<unit>[A-Za-z%]+)/.match(v)
|
168
|
+
v = LSI::BBU::NumberUnit.new(m[:number].to_f,m[:unit])
|
169
|
+
end
|
170
|
+
c[k] = v
|
171
|
+
end
|
172
|
+
|
173
|
+
def on_attribute_exit(new_state, event, *args)
|
174
|
+
@log.debug " [#{current_state}] exit: entering #{new_state} throught event #{event}; args: #{args}"
|
175
|
+
@context.close if Elesai::LSI::PhysicalDrive === @context.current and event != :attribute_line
|
176
|
+
|
177
|
+
@context.flash!(new_state)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Exit
|
181
|
+
|
182
|
+
def exit_line
|
183
|
+
@log.debug " [#{current_state}] event: exit_line"
|
184
|
+
end
|
185
|
+
|
186
|
+
def on_exit_entry(new_state, event, *args)
|
187
|
+
@log.debug " [#{current_state}] exit: entering #{new_state} through event #{event}; args: #{args}"
|
188
|
+
until @context.current.nil? do
|
189
|
+
@context.close
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
### Parse!
|
194
|
+
|
195
|
+
def parse!(lsi,opts)
|
196
|
+
|
197
|
+
@lsi = lsi
|
198
|
+
@log = Elesai::Logger.instance.log
|
199
|
+
output = nil
|
200
|
+
|
201
|
+
if STDIN.ready?
|
202
|
+
output = $stdin.read
|
203
|
+
else
|
204
|
+
if opts[:fake].start_with? '-'
|
205
|
+
megacli = opts[:megacli].nil? ? "Megacli" : opts[:megacli]
|
206
|
+
command = "#{megacli} #{opts[:fake]} -nolog"
|
207
|
+
command = Process.uid == 0 ? command : "sudo " << command
|
208
|
+
output, stderr_str, status = Open3.capture3(command)
|
209
|
+
raise RuntimeError, stderr_str unless status.exitstatus == 0
|
210
|
+
else
|
211
|
+
output = File.read(opts[:fake])
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
output.each_line do |line|
|
216
|
+
begin
|
217
|
+
line.strip!
|
218
|
+
line.gsub!(/^=+$/,'')
|
219
|
+
next if line == ''
|
220
|
+
|
221
|
+
match_flag = false
|
222
|
+
@megacli.each do |k, v|
|
223
|
+
if line =~ v[:re]
|
224
|
+
v[:method].call(k,v[:re].match(line))
|
225
|
+
match_flag = true
|
226
|
+
break
|
227
|
+
else
|
228
|
+
match_flag = false
|
229
|
+
next
|
230
|
+
end
|
231
|
+
end
|
232
|
+
raise StandardError, "cannot parse '#{line}'" unless match_flag
|
233
|
+
rescue ArgumentError # ignore lines with invalid byte sequence in UTF-8
|
234
|
+
next
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
end end
|