rubyipmi 0.6.0 → 0.7.0
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.
- checksums.yaml +15 -0
- data/Gemfile +5 -3
- data/README.md +24 -14
- data/Rakefile +82 -4
- data/VERSION +1 -1
- data/lib/rubyipmi.rb +36 -14
- data/lib/rubyipmi/commands/basecommand.rb +57 -119
- data/lib/rubyipmi/freeipmi/commands/basecommand.rb +29 -25
- data/lib/rubyipmi/freeipmi/commands/bmc.rb +3 -3
- data/lib/rubyipmi/freeipmi/commands/bmcconfig.rb +6 -6
- data/lib/rubyipmi/freeipmi/commands/bmcinfo.rb +3 -23
- data/lib/rubyipmi/freeipmi/commands/fru.rb +117 -23
- data/lib/rubyipmi/freeipmi/commands/lan.rb +32 -37
- data/lib/rubyipmi/freeipmi/commands/power.rb +1 -1
- data/lib/rubyipmi/freeipmi/commands/sensors.rb +53 -50
- data/lib/rubyipmi/freeipmi/connection.rb +16 -2
- data/lib/rubyipmi/freeipmi/errorcodes.rb +25 -2
- data/lib/rubyipmi/ipmitool/commands/basecommand.rb +20 -37
- data/lib/rubyipmi/ipmitool/commands/bmc.rb +1 -24
- data/lib/rubyipmi/ipmitool/commands/chassis.rb +1 -0
- data/lib/rubyipmi/ipmitool/commands/fru.rb +112 -30
- data/lib/rubyipmi/ipmitool/commands/lan.rb +55 -77
- data/lib/rubyipmi/ipmitool/commands/power.rb +10 -4
- data/lib/rubyipmi/ipmitool/commands/sensors.rb +53 -80
- data/lib/rubyipmi/ipmitool/connection.rb +19 -3
- data/lib/rubyipmi/ipmitool/errorcodes.rb +51 -3
- data/rubyipmi.gemspec +73 -33
- data/spec/Vagrantfile +45 -0
- data/spec/fixtures/freeipmi/bmc_config.txt +317 -0
- data/spec/fixtures/freeipmi/bmc_config_lan_conf.txt +19 -0
- data/spec/fixtures/freeipmi/bmc_info.txt +32 -0
- data/spec/fixtures/freeipmi/errors.txt +3 -0
- data/spec/fixtures/freeipmi/fru.txt +13 -0
- data/spec/fixtures/freeipmi/sensors.txt +29 -0
- data/spec/fixtures/ipmitool/bmc_info.txt +20 -0
- data/spec/fixtures/ipmitool/errors.txt +10 -0
- data/spec/fixtures/ipmitool/fru.txt +96 -0
- data/spec/fixtures/ipmitool/lan.txt +17 -0
- data/spec/fixtures/ipmitool/sensors.txt +105 -0
- data/spec/integration/bmc_spec.rb +49 -0
- data/spec/{chassis_config_spec.rb → integration/chassis_config_spec.rb} +6 -6
- data/spec/integration/chassis_spec.rb +26 -0
- data/spec/integration/connection_spec.rb +35 -0
- data/spec/{fru_spec.rb → integration/fru_spec.rb} +11 -10
- data/spec/{lan_spec.rb → integration/lan_spec.rb} +9 -7
- data/spec/integration/power_spec.rb +40 -0
- data/spec/{rubyipmi_spec.rb → integration/rubyipmi_spec.rb} +7 -10
- data/spec/{sensor_spec.rb → integration/sensor_spec.rb} +5 -20
- data/spec/manifests/default.pp +50 -0
- data/spec/puppetmodules/archive/LICENSE-2.0.txt +202 -0
- data/spec/puppetmodules/archive/Modulefile +8 -0
- data/spec/puppetmodules/archive/README.md +40 -0
- data/spec/puppetmodules/archive/manifests/download.pp +157 -0
- data/spec/puppetmodules/archive/manifests/extract.pp +81 -0
- data/spec/puppetmodules/archive/manifests/init.pp +70 -0
- data/spec/puppetmodules/archive/manifests/tar-gz.pp +7 -0
- data/spec/puppetmodules/archive/manifests/zip.pp +7 -0
- data/spec/puppetmodules/archive/metadata.json +26 -0
- data/spec/spec_helper.rb +35 -3
- data/spec/unit/freeipmi/bmc-info_spec.rb +42 -0
- data/spec/unit/freeipmi/bmc_spec.rb +44 -0
- data/spec/unit/freeipmi/connection_spec.rb +56 -0
- data/spec/unit/freeipmi/errorcodes_spec.rb +34 -0
- data/spec/unit/freeipmi/fru_spec.rb +77 -0
- data/spec/unit/freeipmi/lan_spec.rb +0 -0
- data/spec/unit/freeipmi/sensors_spec.rb +83 -0
- data/spec/unit/ipmitool/bmc_spec.rb +78 -0
- data/spec/unit/ipmitool/connection_spec.rb +58 -0
- data/spec/unit/ipmitool/errorcodes_spec.rb +34 -0
- data/spec/unit/ipmitool/fru_spec.rb +77 -0
- data/spec/unit/ipmitool/lan_spec.rb +93 -0
- data/spec/unit/ipmitool/sensors_spec.rb +95 -0
- data/spec/unit/rubyipmi_spec.rb +31 -0
- data/spec/vagrant +27 -0
- data/spec/vagrant.pub +1 -0
- metadata +157 -106
- data/.document +0 -5
- data/.rspec +0 -1
- data/Gemfile.lock +0 -33
- data/spec/bmc_spec.rb +0 -46
- data/spec/chassis_spec.rb +0 -26
- data/spec/connection_spec.rb +0 -31
- data/spec/power_spec.rb +0 -42
@@ -6,103 +6,106 @@ module Rubyipmi::Freeipmi
|
|
6
6
|
super("ipmi-sensors", opts)
|
7
7
|
@options["no-header-output"] = false
|
8
8
|
@options["output-sensor-state"] = false
|
9
|
+
@options["entity-sensor-names"] = false
|
9
10
|
end
|
10
11
|
|
11
12
|
def refresh
|
12
13
|
@sensors = nil
|
13
|
-
|
14
|
+
list
|
14
15
|
end
|
15
16
|
|
16
17
|
def list
|
17
|
-
sensors
|
18
|
+
@sensors ||= parse(getsensors)
|
18
19
|
end
|
19
20
|
|
20
21
|
def count
|
21
|
-
|
22
|
+
list.count
|
22
23
|
end
|
23
24
|
|
24
25
|
def names
|
25
|
-
|
26
|
+
list.keys
|
26
27
|
end
|
27
28
|
|
29
|
+
# returns a hash of fan sensors where the key is fan name and value is the sensor
|
28
30
|
def fanlist(refreshdata=false)
|
29
31
|
refresh if refreshdata
|
30
|
-
flist =
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
if match[1] == "fan"
|
35
|
-
num = (match[2].to_i) -1
|
36
|
-
flist[num] = sensor.last[:value]
|
32
|
+
flist = {}
|
33
|
+
list.each do | name,sensor |
|
34
|
+
if name =~ /.*fan.*/
|
35
|
+
flist[name] = sensor
|
37
36
|
end
|
38
37
|
end
|
39
|
-
flist
|
38
|
+
return flist
|
40
39
|
end
|
41
40
|
|
41
|
+
# returns a hash of sensors where each key is the name of the sensor and the value is the sensor
|
42
42
|
def templist(refreshdata=false)
|
43
43
|
refresh if refreshdata
|
44
|
-
tlist =
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
if match[1] == "temp"
|
49
|
-
num = (match[2].to_i) -1
|
50
|
-
tlist[num] = sensor.last[:value]
|
44
|
+
tlist = {}
|
45
|
+
list.each do | name , sensor |
|
46
|
+
if sensor[:unit] =~ /.*degree.*/ || name =~ /.*temp.*/
|
47
|
+
tlist[name] = sensor
|
51
48
|
end
|
52
49
|
end
|
53
|
-
tlist
|
50
|
+
return tlist
|
54
51
|
end
|
55
52
|
|
56
|
-
|
53
|
+
def getsensors
|
54
|
+
value = runcmd
|
55
|
+
return @result
|
56
|
+
end
|
57
57
|
|
58
58
|
private
|
59
59
|
|
60
|
-
def sensors
|
61
|
-
@sensors ||= parse(getsensors)
|
62
|
-
end
|
63
|
-
|
64
60
|
def method_missing(method, *args, &block)
|
65
|
-
if not
|
61
|
+
if not list.has_key?(method.to_s)
|
66
62
|
raise NoMethodError
|
67
63
|
else
|
68
|
-
|
64
|
+
list[method.to_s]
|
69
65
|
end
|
70
66
|
end
|
71
67
|
|
72
|
-
|
73
|
-
def getsensors
|
74
|
-
value = runcmd
|
75
|
-
@result
|
76
|
-
end
|
77
|
-
|
78
68
|
def parse(data)
|
79
69
|
sensorlist = {}
|
80
|
-
data.
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
sensor[:type] = data[1].strip
|
87
|
-
sensor[:state] = data[2].strip
|
88
|
-
sensor[:value] = data[3].strip
|
89
|
-
sensor[:unit] = data[4].strip
|
90
|
-
sensor[:status] = data[5].strip
|
91
|
-
sensorlist[sensor[:name]] = sensor
|
92
|
-
|
70
|
+
if ! data.nil?
|
71
|
+
data.lines.each do | line|
|
72
|
+
# skip the header
|
73
|
+
sensor = Sensor.new(line)
|
74
|
+
sensorlist[sensor[:name]] = sensor
|
75
|
+
end
|
93
76
|
end
|
94
77
|
return sensorlist
|
95
|
-
|
96
78
|
end
|
79
|
+
|
97
80
|
end
|
98
81
|
|
99
82
|
class Sensor < Hash
|
83
|
+
def initialize(line)
|
84
|
+
parse(line)
|
85
|
+
self[:name] = normalize(self[:name])
|
86
|
+
end
|
100
87
|
|
101
|
-
|
102
|
-
|
103
|
-
|
88
|
+
private
|
89
|
+
def normalize(text)
|
90
|
+
text.gsub(/\ /, '_').gsub(/\./, '').downcase
|
104
91
|
end
|
105
92
|
|
93
|
+
# Parse the individual sensor
|
94
|
+
# Note: not all fields will exist on every server
|
95
|
+
def parse(line)
|
96
|
+
fields = [:id_num, :name, :value, :unit, :status, :type, :state, :lower_nonrec,
|
97
|
+
:lower_crit,:lower_noncrit, :upper_crit, :upper_nonrec, :asserts_enabled, :deasserts_enabled ]
|
98
|
+
data = line.split(/\|/)
|
99
|
+
# should we ever encounter a field not in the fields list, just use a counter based fieldname so we just
|
100
|
+
# use field1, field2, field3, ...
|
101
|
+
i = 0
|
102
|
+
data.each do | value |
|
103
|
+
field ||= fields.shift || "field#{i}"
|
104
|
+
self[field] = value.strip
|
105
|
+
i = i.next
|
106
|
+
end
|
107
|
+
end
|
106
108
|
end
|
109
|
+
|
107
110
|
end
|
108
111
|
|
@@ -14,7 +14,7 @@ module Rubyipmi
|
|
14
14
|
attr_accessor :options
|
15
15
|
|
16
16
|
|
17
|
-
def initialize(user, pass, host)
|
17
|
+
def initialize(user, pass, host,debug=false)
|
18
18
|
@options = Rubyipmi::ObservableHash.new
|
19
19
|
raise("Must provide a host to connect to") unless host
|
20
20
|
@options["hostname"] = host
|
@@ -22,7 +22,7 @@ module Rubyipmi
|
|
22
22
|
# So they are not required
|
23
23
|
@options["username"] = user if user
|
24
24
|
@options["password"] = pass if pass
|
25
|
-
|
25
|
+
#@options["driver-type"] = 'LAN_2_0'
|
26
26
|
#getWorkArounds
|
27
27
|
end
|
28
28
|
|
@@ -46,6 +46,20 @@ module Rubyipmi
|
|
46
46
|
@sensors ||= Rubyipmi::Freeipmi::Sensors.new(@options)
|
47
47
|
end
|
48
48
|
|
49
|
+
def get_diag
|
50
|
+
data = {}
|
51
|
+
data['provider'] = provider
|
52
|
+
if @fru
|
53
|
+
data['frus'] = @fru.getfrus
|
54
|
+
end
|
55
|
+
if @sensors
|
56
|
+
data['sensors'] = @sensors.getsensors
|
57
|
+
end
|
58
|
+
if @bmc
|
59
|
+
data['bmc_info'] = @bmc.info
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
49
63
|
end
|
50
64
|
end
|
51
65
|
end
|
@@ -2,14 +2,37 @@ module Rubyipmi::Freeipmi
|
|
2
2
|
|
3
3
|
class ErrorCodes
|
4
4
|
|
5
|
-
@@
|
5
|
+
@@codes = {
|
6
6
|
"authentication type unavailable for attempted privilege level" => {"driver-type" => "LAN_2_0"},
|
7
|
+
"authentication type unavailable for attempted privilege level\n" => {"driver-type" => "LAN_2_0"},
|
7
8
|
|
8
9
|
}
|
9
10
|
|
11
|
+
def self.length
|
12
|
+
@@codes.length
|
13
|
+
end
|
14
|
+
|
10
15
|
def self.code
|
11
|
-
@@
|
16
|
+
@@codes
|
12
17
|
end
|
18
|
+
|
19
|
+
def self.search(code)
|
20
|
+
# example error code:
|
21
|
+
# "/usr/local/sbin/bmc-info: authentication type unavailable for attempted privilege level\n"
|
22
|
+
code.chomp! # clean up newline
|
23
|
+
code = code.split(':').last.strip # clean up left hand side and strip white space from sides
|
24
|
+
fix = @@codes.fetch(code,nil)
|
25
|
+
if fix.nil?
|
26
|
+
@@codes.each do | error, result |
|
27
|
+
if code =~ /.*#{error}.*/i
|
28
|
+
fix = result
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
raise "No Fix found" if fix.nil?
|
33
|
+
return fix
|
34
|
+
end
|
35
|
+
|
13
36
|
end
|
14
37
|
|
15
38
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rubyipmi/ipmitool/errorcodes'
|
2
|
+
|
1
3
|
module Rubyipmi::Ipmitool
|
2
4
|
|
3
5
|
class BaseCommand < Rubyipmi::BaseCommand
|
@@ -5,68 +7,49 @@ module Rubyipmi::Ipmitool
|
|
5
7
|
def setpass
|
6
8
|
super
|
7
9
|
@options["f"] = @passfile.path
|
8
|
-
@passfile.
|
10
|
+
@passfile.write "#{@options["P"]}"
|
11
|
+
@passfile.rewind
|
9
12
|
@passfile.close
|
13
|
+
end
|
10
14
|
|
11
|
-
|
15
|
+
def max_retry_count
|
16
|
+
@max_retry_count ||= Rubyipmi::Ipmitool::ErrorCodes.length
|
12
17
|
end
|
13
18
|
|
14
19
|
def makecommand
|
15
|
-
args =
|
20
|
+
args = ''
|
16
21
|
# need to format the options to ipmitool format
|
17
22
|
@options.each do |k,v|
|
23
|
+
# must remove from command line as its handled via conf file
|
24
|
+
next if k == "P"
|
18
25
|
next if k == "cmdargs"
|
19
|
-
args << "-#{k} #{v}
|
26
|
+
args << " -#{k} #{v}"
|
20
27
|
end
|
21
|
-
# must remove from command line as its handled via conf file
|
22
|
-
args.delete("-P")
|
23
28
|
|
24
29
|
# since ipmitool requires commands to be in specific order
|
25
|
-
args << " " + options["cmdargs"]
|
26
30
|
|
27
|
-
|
28
|
-
end
|
31
|
+
args << ' ' + options.fetch('cmdargs', '')
|
29
32
|
|
33
|
+
return "#{cmd} #{args.lstrip}"
|
34
|
+
end
|
30
35
|
|
31
36
|
# The findfix method acts like a recursive method and applies fixes defined in the errorcodes
|
32
37
|
# If a fix is found it is applied to the options hash, and then the last run command is retried
|
33
38
|
# until all the fixes are exhausted or a error not defined in the errorcodes is found
|
34
|
-
def
|
39
|
+
def find_fix(result)
|
35
40
|
if result
|
36
41
|
# The errorcode code hash contains the fix
|
37
|
-
|
38
|
-
|
39
|
-
if not fix
|
40
|
-
raise "#{result}"
|
41
|
-
else
|
42
|
+
begin
|
43
|
+
fix = ErrorCodes.search(result)
|
42
44
|
@options.merge_notify!(fix)
|
43
|
-
# retry the last called method
|
44
|
-
# its quicker to explicitly call these commands than calling a command block
|
45
|
-
if runmethod == "runcmd"
|
46
|
-
runcmd(debug)
|
47
|
-
else
|
48
|
-
runcmd_without_opts(args, debug)
|
49
|
-
end
|
50
45
|
|
46
|
+
rescue
|
47
|
+
raise "Could not find fix for error code: \n#{result}"
|
51
48
|
end
|
52
|
-
|
53
49
|
end
|
54
50
|
end
|
55
|
-
def throwError
|
56
|
-
# Find out what kind of error is happening, parse results
|
57
|
-
# Check for authentication or connection issue
|
58
|
-
#puts "ipmi call: #{@lastcall}"
|
59
51
|
|
60
|
-
|
61
|
-
code = "ipmi call: #{@lastcall} timed out"
|
62
|
-
raise code
|
63
|
-
else
|
64
|
-
# ipmitool spits out many errors so for now we will just take the first error
|
65
|
-
code = @result.split(/\r\n/).first if not @result.empty?
|
66
|
-
end
|
67
|
-
throw :ipmierror, code
|
68
|
-
end
|
52
|
+
end
|
69
53
|
|
70
54
|
|
71
|
-
end
|
72
55
|
end
|
@@ -49,29 +49,6 @@ module Rubyipmi::Ipmitool
|
|
49
49
|
|
50
50
|
end
|
51
51
|
|
52
|
-
# Some sample data for info
|
53
|
-
# Device ID : 17
|
54
|
-
# Device Revision : 1
|
55
|
-
# Firmware Revision : 2.9
|
56
|
-
# IPMI Version : 2.0
|
57
|
-
# Manufacturer ID : 11
|
58
|
-
# Manufacturer Name : Hewlett-Packard
|
59
|
-
# Product ID : 8192 (0x2000)
|
60
|
-
# Product Name : Unknown (0x2000)
|
61
|
-
# Device Available : yes
|
62
|
-
# Provides Device SDRs : yes
|
63
|
-
# Additional Device Support :
|
64
|
-
# Sensor Device
|
65
|
-
# SDR Repository Device
|
66
|
-
# SEL Device
|
67
|
-
# FRU Inventory Device
|
68
|
-
# Aux Firmware Rev Info :
|
69
|
-
# 0x00
|
70
|
-
# 0x00
|
71
|
-
# 0x00
|
72
|
-
# 0x30
|
73
|
-
|
74
|
-
|
75
52
|
# This function will get the bmcinfo and return a hash of each item in the info
|
76
53
|
def retrieve
|
77
54
|
@options["cmdargs"] = "bmc info"
|
@@ -87,7 +64,7 @@ module Rubyipmi::Ipmitool
|
|
87
64
|
key = item.first.strip
|
88
65
|
value = item.last.strip
|
89
66
|
# if the following condition is met we have subvalues
|
90
|
-
if
|
67
|
+
if value.empty?
|
91
68
|
subkey = key
|
92
69
|
@bmcinfo[subkey] = []
|
93
70
|
elsif key == value and subkey
|
@@ -2,62 +2,144 @@ module Rubyipmi::Ipmitool
|
|
2
2
|
|
3
3
|
class Fru < Rubyipmi::Ipmitool::BaseCommand
|
4
4
|
|
5
|
+
attr_accessor :list
|
6
|
+
|
7
|
+
DEFAULT_FRU = 'builtin_fru_device'
|
8
|
+
|
9
|
+
|
5
10
|
def initialize(opts = ObservableHash.new)
|
6
11
|
super("ipmitool", opts)
|
12
|
+
@list = {}
|
7
13
|
end
|
8
14
|
|
9
|
-
|
10
|
-
|
11
|
-
|
15
|
+
def names
|
16
|
+
list.keys
|
17
|
+
end
|
18
|
+
|
19
|
+
def manufacturer
|
20
|
+
list[DEFAULT_FRU]['product_manufacturer']
|
12
21
|
end
|
13
22
|
|
14
|
-
# returns the serial of the board
|
15
23
|
def serial
|
16
|
-
|
24
|
+
list[DEFAULT_FRU]['board_serial']
|
17
25
|
end
|
18
26
|
|
19
|
-
|
20
|
-
|
21
|
-
list["product_manufacturer"]
|
27
|
+
def model
|
28
|
+
list[DEFAULT_FRU]['product_manufacturer']
|
22
29
|
end
|
23
30
|
|
24
|
-
#
|
25
|
-
def
|
26
|
-
|
31
|
+
# return the list of fru information in a hash
|
32
|
+
def list
|
33
|
+
if @list.count < 1
|
34
|
+
parse(getfrus)
|
35
|
+
end
|
36
|
+
@list
|
37
|
+
end
|
38
|
+
|
39
|
+
# method to retrieve the raw fru data
|
40
|
+
def getfrus
|
41
|
+
command
|
27
42
|
end
|
28
43
|
|
29
44
|
private
|
30
45
|
|
46
|
+
# I use method missing to allow the user to say Fru.<name> which returns a frudata object unless the user
|
47
|
+
# passes a keyname from the default fru device
|
31
48
|
def method_missing(method, *args, &block)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
49
|
+
name = method.to_s
|
50
|
+
fru = list.fetch(name, nil)
|
51
|
+
# if the user wanted some data from the default fru, lets show the data for the fru. Otherwise
|
52
|
+
# we return the Fru with the given name
|
53
|
+
if fru.nil?
|
54
|
+
if list[DEFAULT_FRU].keys.include?(name)
|
55
|
+
return list[DEFAULT_FRU][name]
|
56
|
+
else
|
57
|
+
# maybe we should return nil instead? hmm...
|
58
|
+
raise NoMethodError
|
59
|
+
end
|
60
|
+
else
|
61
|
+
return fru
|
62
|
+
end
|
63
|
+
end
|
38
64
|
|
39
65
|
# parse the fru information
|
40
66
|
def parse(data)
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
67
|
+
if ! data.nil?
|
68
|
+
parsed_data = []
|
69
|
+
data.lines.each do |line|
|
70
|
+
if line =~ /^FRU.*/
|
71
|
+
# this is the either the first line of of the fru or another fru
|
72
|
+
if parsed_data.count != 0
|
73
|
+
# we have reached a new fru device so lets record the previous fru
|
74
|
+
new_fru = FruData.new(parsed_data)
|
75
|
+
parsed_data = []
|
76
|
+
@list[new_fru[:name]] = new_fru
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
parsed_data << line
|
81
|
+
end
|
82
|
+
# process the last fru
|
83
|
+
if parsed_data.count != 0
|
84
|
+
# we have reached a new fru device so lets record the previous fru
|
85
|
+
new_fru = FruData.new(parsed_data)
|
86
|
+
parsed_data = []
|
87
|
+
@list[new_fru[:name]] = new_fru
|
88
|
+
end
|
47
89
|
end
|
48
|
-
return datalist
|
49
90
|
end
|
50
91
|
|
51
92
|
# run the command and return result
|
52
93
|
def command
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
94
|
+
@options["cmdargs"] = "fru"
|
95
|
+
value = runcmd
|
96
|
+
@options.delete_notify("cmdargs")
|
97
|
+
if value
|
98
|
+
return @result
|
99
|
+
end
|
59
100
|
end
|
60
101
|
|
61
102
|
end
|
62
103
|
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
class FruData < Hash
|
108
|
+
|
109
|
+
def name
|
110
|
+
self[:name]
|
111
|
+
end
|
112
|
+
|
113
|
+
def initialize(data)
|
114
|
+
parse(data)
|
115
|
+
end
|
116
|
+
|
117
|
+
# parse the fru information that should be an array of lines
|
118
|
+
def parse(data)
|
119
|
+
if ! data.nil?
|
120
|
+
data.each do |line|
|
121
|
+
key, value = line.split(':', 2)
|
122
|
+
if key =~ /^FRU\s+Device.*/
|
123
|
+
if value =~ /([\w\s]*)\(.*\)/
|
124
|
+
self[:name] = $~[1].strip.gsub(/\ /, '_').downcase
|
125
|
+
end
|
126
|
+
else
|
127
|
+
key = key.strip.gsub(/\ /, '_').downcase
|
128
|
+
if ! value.nil?
|
129
|
+
self[key] = value.strip
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def method_missing(method, *args, &block)
|
139
|
+
self.fetch(method.to_s, nil)
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
|
63
145
|
end
|