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.
Files changed (83) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +5 -3
  3. data/README.md +24 -14
  4. data/Rakefile +82 -4
  5. data/VERSION +1 -1
  6. data/lib/rubyipmi.rb +36 -14
  7. data/lib/rubyipmi/commands/basecommand.rb +57 -119
  8. data/lib/rubyipmi/freeipmi/commands/basecommand.rb +29 -25
  9. data/lib/rubyipmi/freeipmi/commands/bmc.rb +3 -3
  10. data/lib/rubyipmi/freeipmi/commands/bmcconfig.rb +6 -6
  11. data/lib/rubyipmi/freeipmi/commands/bmcinfo.rb +3 -23
  12. data/lib/rubyipmi/freeipmi/commands/fru.rb +117 -23
  13. data/lib/rubyipmi/freeipmi/commands/lan.rb +32 -37
  14. data/lib/rubyipmi/freeipmi/commands/power.rb +1 -1
  15. data/lib/rubyipmi/freeipmi/commands/sensors.rb +53 -50
  16. data/lib/rubyipmi/freeipmi/connection.rb +16 -2
  17. data/lib/rubyipmi/freeipmi/errorcodes.rb +25 -2
  18. data/lib/rubyipmi/ipmitool/commands/basecommand.rb +20 -37
  19. data/lib/rubyipmi/ipmitool/commands/bmc.rb +1 -24
  20. data/lib/rubyipmi/ipmitool/commands/chassis.rb +1 -0
  21. data/lib/rubyipmi/ipmitool/commands/fru.rb +112 -30
  22. data/lib/rubyipmi/ipmitool/commands/lan.rb +55 -77
  23. data/lib/rubyipmi/ipmitool/commands/power.rb +10 -4
  24. data/lib/rubyipmi/ipmitool/commands/sensors.rb +53 -80
  25. data/lib/rubyipmi/ipmitool/connection.rb +19 -3
  26. data/lib/rubyipmi/ipmitool/errorcodes.rb +51 -3
  27. data/rubyipmi.gemspec +73 -33
  28. data/spec/Vagrantfile +45 -0
  29. data/spec/fixtures/freeipmi/bmc_config.txt +317 -0
  30. data/spec/fixtures/freeipmi/bmc_config_lan_conf.txt +19 -0
  31. data/spec/fixtures/freeipmi/bmc_info.txt +32 -0
  32. data/spec/fixtures/freeipmi/errors.txt +3 -0
  33. data/spec/fixtures/freeipmi/fru.txt +13 -0
  34. data/spec/fixtures/freeipmi/sensors.txt +29 -0
  35. data/spec/fixtures/ipmitool/bmc_info.txt +20 -0
  36. data/spec/fixtures/ipmitool/errors.txt +10 -0
  37. data/spec/fixtures/ipmitool/fru.txt +96 -0
  38. data/spec/fixtures/ipmitool/lan.txt +17 -0
  39. data/spec/fixtures/ipmitool/sensors.txt +105 -0
  40. data/spec/integration/bmc_spec.rb +49 -0
  41. data/spec/{chassis_config_spec.rb → integration/chassis_config_spec.rb} +6 -6
  42. data/spec/integration/chassis_spec.rb +26 -0
  43. data/spec/integration/connection_spec.rb +35 -0
  44. data/spec/{fru_spec.rb → integration/fru_spec.rb} +11 -10
  45. data/spec/{lan_spec.rb → integration/lan_spec.rb} +9 -7
  46. data/spec/integration/power_spec.rb +40 -0
  47. data/spec/{rubyipmi_spec.rb → integration/rubyipmi_spec.rb} +7 -10
  48. data/spec/{sensor_spec.rb → integration/sensor_spec.rb} +5 -20
  49. data/spec/manifests/default.pp +50 -0
  50. data/spec/puppetmodules/archive/LICENSE-2.0.txt +202 -0
  51. data/spec/puppetmodules/archive/Modulefile +8 -0
  52. data/spec/puppetmodules/archive/README.md +40 -0
  53. data/spec/puppetmodules/archive/manifests/download.pp +157 -0
  54. data/spec/puppetmodules/archive/manifests/extract.pp +81 -0
  55. data/spec/puppetmodules/archive/manifests/init.pp +70 -0
  56. data/spec/puppetmodules/archive/manifests/tar-gz.pp +7 -0
  57. data/spec/puppetmodules/archive/manifests/zip.pp +7 -0
  58. data/spec/puppetmodules/archive/metadata.json +26 -0
  59. data/spec/spec_helper.rb +35 -3
  60. data/spec/unit/freeipmi/bmc-info_spec.rb +42 -0
  61. data/spec/unit/freeipmi/bmc_spec.rb +44 -0
  62. data/spec/unit/freeipmi/connection_spec.rb +56 -0
  63. data/spec/unit/freeipmi/errorcodes_spec.rb +34 -0
  64. data/spec/unit/freeipmi/fru_spec.rb +77 -0
  65. data/spec/unit/freeipmi/lan_spec.rb +0 -0
  66. data/spec/unit/freeipmi/sensors_spec.rb +83 -0
  67. data/spec/unit/ipmitool/bmc_spec.rb +78 -0
  68. data/spec/unit/ipmitool/connection_spec.rb +58 -0
  69. data/spec/unit/ipmitool/errorcodes_spec.rb +34 -0
  70. data/spec/unit/ipmitool/fru_spec.rb +77 -0
  71. data/spec/unit/ipmitool/lan_spec.rb +93 -0
  72. data/spec/unit/ipmitool/sensors_spec.rb +95 -0
  73. data/spec/unit/rubyipmi_spec.rb +31 -0
  74. data/spec/vagrant +27 -0
  75. data/spec/vagrant.pub +1 -0
  76. metadata +157 -106
  77. data/.document +0 -5
  78. data/.rspec +0 -1
  79. data/Gemfile.lock +0 -33
  80. data/spec/bmc_spec.rb +0 -46
  81. data/spec/chassis_spec.rb +0 -26
  82. data/spec/connection_spec.rb +0 -31
  83. data/spec/power_spec.rb +0 -42
@@ -1,3 +1,5 @@
1
+ require 'rubyipmi/freeipmi/errorcodes'
2
+
1
3
  module Rubyipmi::Freeipmi
2
4
 
3
5
  class BaseCommand < Rubyipmi::BaseCommand
@@ -5,27 +7,29 @@ module Rubyipmi::Freeipmi
5
7
  def setpass
6
8
  super
7
9
  @options["config-file"] = @passfile.path
8
- @passfile.puts "password #{@options["password"]}\n"
9
- @passfile.puts "username #{@options["username"]}"
10
-
10
+ @passfile.write "username #{@options["username"]}\n"
11
+ @passfile.write "password #{@options["password"]}\n"
11
12
  @passfile.close
13
+
14
+ end
15
+
16
+ def max_retry_count
17
+ @max_retry_count ||= Rubyipmi::Freeipmi::ErrorCodes.length
12
18
  end
13
19
 
14
20
  def makecommand
15
21
  # need to format the options to freeipmi format
16
22
  args = @options.collect { |k, v|
23
+ # must remove from command line as its handled via conf file
24
+ next if k == 'password'
25
+ next if k == 'username'
17
26
  if not v
18
27
  "--#{k}"
19
28
  else
20
29
  "--#{k}=#{v}"
21
30
  end
22
31
  }.join(" ")
23
- # must remove from command line as its handled via conf file
24
- args.delete("--password")
25
- args.delete("--username")
26
-
27
-
28
- return "#{cmd} #{args}"
32
+ return "#{cmd} #{args.rstrip}"
29
33
  end
30
34
 
31
35
  # This method will check if the results are really valid as the exit code can be misleading and incorrect
@@ -35,39 +39,39 @@ module Rubyipmi::Freeipmi
35
39
  # until ipmipower returns the correct exit status this is a hack
36
40
  # essentially any result greater than 23 characters is an error
37
41
  if @result.length > 23
38
- return false
42
+ raise "Error occurred"
39
43
  end
40
44
  when "bmc-config"
41
45
  if @result.length > 100
42
46
  return true
47
+ else
48
+ raise "Error occurred"
49
+ end
50
+ else
51
+ if exitstatus.success?
52
+ return true
53
+ else
54
+ raise "Error occurred"
43
55
  end
44
- end
45
- return exitstatus.success?
46
56
 
57
+ end
47
58
  end
48
59
 
49
60
  # The findfix method acts like a recursive method and applies fixes defined in the errorcodes
50
61
  # If a fix is found it is applied to the options hash, and then the last run command is retried
51
62
  # until all the fixes are exhausted or a error not defined in the errorcodes is found
52
- def findfix(result, args, debug, runmethod)
63
+ def find_fix(result)
53
64
  if result
54
65
  # The errorcode code hash contains the fix
55
- fix = Rubyipmi::Freeipmi::ErrorCodes.code[result]
56
- if not fix
57
- raise "#{result}"
58
- else
66
+ begin
67
+ fix = ErrorCodes.search(result)
59
68
  @options.merge_notify!(fix)
60
- # retry the last called method
61
- # its quicker to explicitly call these commands than calling a command block
62
- if runmethod == "runcmd"
63
- runcmd(debug)
64
- else
65
- runcmd_without_opts(args, debug)
66
- end
67
69
 
70
+ rescue
71
+ raise "Could not find fix for error code: \n#{result}"
68
72
  end
69
-
70
73
  end
71
74
  end
75
+
72
76
  end
73
77
  end
@@ -1,12 +1,12 @@
1
1
  module Rubyipmi::Freeipmi
2
2
 
3
- class Bmc
3
+ class Bmc < Rubyipmi::Freeipmi::BaseCommand
4
4
 
5
- attr_accessor :options
5
+ #attr_accessor :options
6
6
  attr_accessor :config
7
7
 
8
8
  def initialize(opts = ObservableHash.new)
9
- @options = opts
9
+ super("bmc-device", opts)
10
10
  @bmcinfo = {}
11
11
  end
12
12
 
@@ -9,12 +9,12 @@ module Rubyipmi::Freeipmi
9
9
  end
10
10
 
11
11
  def section(section)
12
- @options["checkout"] = false
13
- @options["section"] = section
14
- value = runcmd
15
- @options.delete_notify("checkout")
16
- @options.delete_notify("section")
17
- @result
12
+ @options["checkout"] = false
13
+ @options["section"] = section
14
+ value = runcmd
15
+ @options.delete_notify("checkout")
16
+ @options.delete_notify("section")
17
+ return @result
18
18
  end
19
19
 
20
20
  def setsection(section, key, value)
@@ -9,9 +9,9 @@ module Rubyipmi::Freeipmi
9
9
 
10
10
 
11
11
  def guid
12
- @options["guid"] = false
12
+ options["get-device-guid"] = false
13
13
  status = runcmd
14
- @options.delete_notify["guid"]
14
+ options.delete_notify("get-device-guid")
15
15
  if not status
16
16
  raise @result
17
17
  else
@@ -19,27 +19,7 @@ module Rubyipmi::Freeipmi
19
19
  end
20
20
 
21
21
  end
22
- # freeipmi
23
- # Device ID: 17
24
- # Device Revision: 1
25
- # [SDR Support]
26
- # Firmware Revision: 2.09
27
- # [Device Available (normal operation)]
28
- # IPMI Version: 2.0
29
- # Additional Device Support:
30
- # [Sensor Device]
31
- # [SDR Repository Device]
32
- # [SEL Device]
33
- # [FRU Inventory Device]
34
- # Manufacturer ID: 11
35
- # Product ID: 8192
36
- # Channel Information:
37
- # Channel No: 2
38
- # Medium Type: 802.3 LAN
39
- # Protocol Type: IPMB-1.0
40
- # Channel No: 7
41
- # Medium Type: OEM
42
- # Protocol Type: KCS
22
+
43
23
  def retrieve
44
24
  bmcinfo = {}
45
25
  status = runcmd
@@ -2,48 +2,105 @@ module Rubyipmi::Freeipmi
2
2
 
3
3
  class Fru < Rubyipmi::Freeipmi::BaseCommand
4
4
 
5
+ attr_accessor :list
6
+
7
+ DEFAULT_FRU = 'default_fru_device'
8
+
5
9
  def initialize(opts = ObservableHash.new)
6
- super("ipmi-fru", opts)
10
+ super("ipmi-fru", opts)
11
+ @list = {}
7
12
  end
8
13
 
9
- # return the list of fru information in a hash
10
- def list
11
- @list ||= parse(command)
14
+ def get_from_list(key)
15
+ if list.has_key?(DEFAULT_FRU)
16
+ if list[DEFAULT_FRU].has_key?(key)
17
+ list[DEFAULT_FRU][key]
18
+ else
19
+ nil
20
+ end
21
+ end
22
+ end
23
+
24
+
25
+ def manufacturer
26
+ get_from_list('board_manufacturer')
27
+ end
28
+
29
+ def board_serial
30
+ get_from_list('board_serial_number')
12
31
  end
13
32
 
14
33
  def serial
15
- list["chassis_serial_number"]
34
+ get_from_list('board_serial_number')
16
35
  end
17
36
 
18
- def manufacturer
19
- list["board_manufacturer"]
37
+ def model
38
+ get_from_list('board_product_name')
39
+ end
40
+
41
+ # method to retrieve the raw fru data
42
+ def getfrus
43
+ command
44
+ return @result
20
45
  end
21
46
 
22
- def product
23
- list["board_product_name"]
47
+ def names
48
+ list.keys
49
+ end
50
+
51
+ # return the list of fru information in a hash
52
+ def list
53
+ if @list.count < 1
54
+ parse(getfrus)
55
+ end
56
+ @list
24
57
  end
25
58
 
26
59
  private
27
60
 
28
61
  def method_missing(method, *args, &block)
29
- if not list.has_key?(method.to_s)
30
- raise NoMethodError
31
- else
32
- list[method.to_s]
33
- end
34
- end
62
+ name = method.to_s
63
+ fru = list.fetch(name, nil)
64
+ # if the user wanted some data from the default fru, lets show the data for the fru. Otherwise
65
+ # we return the Fru with the given name
66
+ if fru.nil?
67
+ if list[DEFAULT_FRU].keys.include?(name)
68
+ return list[DEFAULT_FRU][name]
69
+ else
70
+ # maybe we should return nil instead? hmm...
71
+ raise NoMethodError
72
+ end
73
+ else
74
+ return fru
75
+ end
76
+ end
35
77
 
36
78
  # parse the fru information
37
79
  def parse(data)
38
- datalist = {}
39
- data.lines.each do |line|
40
- key, value = line.split(':')
41
- next if key =~ /\n/
42
- value = value.strip
43
- key = key.gsub(/FRU/, '').strip.gsub(/\ /, '_').downcase
44
- datalist[key] = value.strip
80
+ if ! data.nil? and ! data.empty?
81
+ parsed_data = []
82
+ data.lines.each do |line|
83
+ if line =~ /^FRU.*/
84
+ # this is the either the first line of of the fru or another fru
85
+ if parsed_data.count != 0
86
+ # we have reached a new fru device so lets record the previous fru
87
+ new_fru = FruData.new(parsed_data)
88
+ parsed_data = []
89
+ @list[new_fru[:name]] = new_fru
90
+ end
91
+
92
+ end
93
+ parsed_data << line
94
+ end
95
+ # process the last fru
96
+ if parsed_data.count != 0
97
+ # we have reached a new fru device so lets record the previous fru
98
+ new_fru = FruData.new(parsed_data)
99
+ parsed_data = []
100
+ @list[new_fru[:name]] = new_fru
101
+ end
45
102
  end
46
- return datalist
103
+ return @list
47
104
  end
48
105
 
49
106
  # run the command and return result
@@ -56,4 +113,41 @@ module Rubyipmi::Freeipmi
56
113
 
57
114
  end
58
115
 
116
+ class FruData < Hash
117
+
118
+ def name
119
+ self[:name]
120
+ end
121
+
122
+ def initialize(data)
123
+ parse(data)
124
+ end
125
+
126
+ # parse the fru information that should be an array of lines
127
+ def parse(data)
128
+ if ! data.nil?
129
+ data.each do |line|
130
+ key, value = line.split(':', 2)
131
+ if key =~ /^FRU.*/
132
+ if value =~ /([\w\s]*)\(.*\)/
133
+ self[:name] = $~[1].strip.gsub(/\ /, '_').downcase
134
+ end
135
+ else
136
+ key = key.strip.gsub(/\ /, '_').downcase.gsub(/fru_/, '')
137
+ if ! value.nil?
138
+ self[key] = value.strip
139
+
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ private
147
+
148
+ def method_missing(method, *args, &block)
149
+ self.fetch(method.to_s, nil)
150
+ end
151
+
152
+ end
59
153
  end
@@ -13,6 +13,7 @@ module Rubyipmi::Freeipmi
13
13
  @channel = 2
14
14
  end
15
15
 
16
+
16
17
  def info
17
18
  if @info.length < 1
18
19
  parse(@config.section("Lan_Conf"))
@@ -22,45 +23,27 @@ module Rubyipmi::Freeipmi
22
23
  end
23
24
 
24
25
  def dhcp?
25
- if @info.length < 1
26
- parse(@config.section("Lan_Conf"))
27
- end
28
- @info["ip_address_source"].match(/dhcp/i) != nil
26
+ info.fetch("ip_address_source",nil).match(/dhcp/i) != nil
29
27
  end
30
28
 
31
29
  def static?
32
- if @info.length < 1
33
- parse(@config.section("Lan_Conf"))
34
- end
35
- @info["ip_address_source"].match(/static/i) != nil
30
+ info.fetch("ip_address_source",nil).match(/static/i) != nil
36
31
  end
37
32
 
38
33
  def ip
39
- if @info.length < 1
40
- parse(@config.section("Lan_Conf"))
41
- end
42
- @info["ip_address"]
34
+ info.fetch("ip_address", nil)
43
35
  end
44
36
 
45
37
  def mac
46
- if @info.length < 1
47
- parse(@config.section("Lan_Conf"))
48
- end
49
- @info["mac_address"]
38
+ info.fetch("mac_address", nil)
50
39
  end
51
40
 
52
41
  def netmask
53
- if @info.length < 1
54
- parse(@config.section("Lan_Conf"))
55
- end
56
- @info["subnet_mask"]
42
+ info.fetch("subnet_mask", nil)
57
43
  end
58
44
 
59
45
  def gateway
60
- if @info.length < 1
61
- parse(@config.section("Lan_Conf"))
62
- end
63
- @info["default_gateway_ip_address"]
46
+ info.fetch("default_gateway_ip_address", nil)
64
47
  end
65
48
 
66
49
  # def snmp
@@ -75,16 +58,26 @@ module Rubyipmi::Freeipmi
75
58
  #
76
59
  # end
77
60
 
61
+ # validates that the address, returns true/false
62
+ def validaddr?(source)
63
+ valid = /^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/.match("#{source}")
64
+ if valid.nil?
65
+ raise "#{source} is not a valid address"
66
+ else
67
+ return true
68
+ end
69
+ end
70
+
78
71
  def ip=(address)
79
- @config.setsection("Lan_Conf", "IP_Address", address)
72
+ @config.setsection("Lan_Conf", "IP_Address", address) if validaddr?(address)
80
73
  end
81
74
 
82
75
  def netmask=(netmask)
83
- @config.setsection("Lan_Conf", "Subnet_Mask", netmask)
76
+ @config.setsection("Lan_Conf", "Subnet_Mask", netmask) if validaddr?(netmask)
84
77
  end
85
78
 
86
79
  def gateway=(address)
87
- @config.setsection("Lan_Conf", "Default_Gateway_IP_Address", address)
80
+ @config.setsection("Lan_Conf", "Default_Gateway_IP_Address", address) if validaddr?(address)
88
81
  end
89
82
 
90
83
  # def vlanid=(vlan)
@@ -92,16 +85,18 @@ module Rubyipmi::Freeipmi
92
85
  # end
93
86
 
94
87
  def parse(landata)
95
- landata.lines.each do |line|
96
- # clean up the data from spaces
97
- next if line.match(/#+/)
98
- next if line.match(/Section/i)
99
- line.gsub!(/\t/, '')
100
- item = line.split(/\s+/)
101
- key = item.first.strip.downcase
102
- value = item.last.strip
103
- @info[key] = value
104
-
88
+ if ! landata.nil? and ! landata.empty?
89
+ landata.lines.each do |line|
90
+ # clean up the data from spaces
91
+ next if line.match(/#+/)
92
+ next if line.match(/Section/i)
93
+ line.gsub!(/\t/, '')
94
+ item = line.split(/\s+/)
95
+ key = item.first.strip.downcase
96
+ value = item.last.strip
97
+ @info[key] = value
98
+
99
+ end
105
100
  end
106
101
  return @info
107
102
  end