elesai 0.9.3 → 0.10.5

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