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