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
@@ -4,6 +4,7 @@ module Rubyipmi::Ipmitool
4
4
 
5
5
  attr_accessor :info
6
6
  attr_accessor :channel
7
+ MAX_RETRY = 1
7
8
 
8
9
  def initialize(opts = ObservableHash.new)
9
10
  super("ipmitool", opts)
@@ -12,65 +13,58 @@ module Rubyipmi::Ipmitool
12
13
 
13
14
  end
14
15
 
16
+ # sets the info var to be empty causing the variable to repopulate upon the next call to info
17
+ def refresh
18
+ @info = {}
19
+ end
20
+
21
+ def channel=(num)
22
+ refresh
23
+ @channel = num
24
+ end
25
+
15
26
  def info
27
+ retrycount = 0
16
28
  if @info.length < 1
17
- parse(print)
29
+ begin
30
+ parse(print)
31
+ rescue
32
+ # sometimes we need to get the info from channel 1,
33
+ # wait for error to occur then retry using channel 1
34
+ if retrycount < MAX_RETRY
35
+ @channel = 1
36
+ retry
37
+ end
38
+ end
18
39
  else
40
+ # return the cached info
19
41
  @info
20
42
  end
21
43
  end
22
44
 
23
- def print
24
- @options["cmdargs"] = "lan print"
25
- value = runcmd
26
- @options.delete_notify("cmdargs")
27
- if value
28
- @result
29
- end
45
+ def snmp
46
+ info.fetch("snmp_community_string",nil)
30
47
  end
31
48
 
32
- # def snmp
33
- # if @info.length < 1
34
- # parse(print)
35
- # end
36
- # # Some systems do not report the snmp string
37
- # @info["snmp community string"]
38
- # end
39
-
40
49
  def ip
41
- if @info.length < 1
42
- parse(print)
43
- end
44
- @info["ip address"]
50
+ info.fetch("ip_address",nil)
45
51
  end
46
52
 
47
53
  def mac
48
- if @info.length < 1
49
- parse(print)
50
- end
51
- @info["mac address"]
54
+ info.fetch("mac_address",nil)
52
55
  end
53
56
 
54
57
  def netmask
55
- if @info.length < 1
56
- parse(print)
57
- end
58
- @info["subnet mask"]
58
+ info.fetch("subnet_mask",nil)
59
59
  end
60
60
 
61
61
  def gateway
62
- if @info.length < 1
63
- parse(print)
64
- end
65
- @info["default gateway ip"]
62
+ info.fetch("default_gateway_ip",nil)
66
63
  end
67
64
 
68
- # def vlanid
69
- # if @info.length < 1
70
- # parse(print)
71
- # end
72
- # @info["802.1q vlan id"]
73
- # end
65
+ def vlanid
66
+ info.fetch("802.1q_vlan_id",nil)
67
+ end
74
68
 
75
69
  # def snmp=(community)
76
70
  # @options["cmdargs"] = "lan set #{channel} snmp #{community}"
@@ -94,42 +88,43 @@ module Rubyipmi::Ipmitool
94
88
  end
95
89
 
96
90
  def gateway=(address)
97
- @options["cmdargs"] = "lan set #{channel} defgw #{address}"
91
+ @options["cmdargs"] = "lan set #{channel} defgw ipaddr #{address}"
98
92
  value = runcmd
99
93
  @options.delete_notify("cmdargs")
100
94
  return value
101
95
  end
102
96
 
103
97
  def dhcp?
104
- if @info.length < 1
105
- parse(print)
106
- end
107
- @info["ip address source"].match(/dhcp/i) != nil
98
+ info.fetch("ip_address_source",nil).match(/dhcp/i) != nil
108
99
  end
109
100
 
110
101
  def static?
111
- if @info.length < 1
112
- parse(print)
113
- end
114
- @info["ip address source"].match(/static/i) != nil
102
+ info.fetch("ip_address_source",nil).match(/static/i) != nil
115
103
  end
116
104
 
117
- # def vlanid=(vlan)
118
- # @options["cmdargs"] = "lan set #{channel} vlan id #{vlan}"
119
- # value = runcmd
120
- # @options.delete_notify("cmdargs")
121
- # return value
122
- # end
105
+ def vlanid=(vlan)
106
+ @options["cmdargs"] = "lan set #{channel} vlan id #{vlan}"
107
+ value = runcmd
108
+ @options.delete_notify("cmdargs")
109
+ return value
110
+ end
123
111
 
112
+ private
124
113
 
125
- def parse(landata)
126
- multikey = ""
127
- multivalue = {}
114
+ def print
115
+ @options["cmdargs"] = "lan print"
116
+ value = runcmd
117
+ @options.delete_notify("cmdargs")
118
+ if value
119
+ @result
120
+ end
121
+ end
128
122
 
123
+ def parse(landata)
129
124
  landata.lines.each do |line|
130
125
  # clean up the data from spaces
131
126
  item = line.split(':', 2)
132
- key = item.first.strip.downcase
127
+ key = normalize(item.first.strip)
133
128
  value = item.last.strip
134
129
  @info[key] = value
135
130
 
@@ -137,26 +132,9 @@ module Rubyipmi::Ipmitool
137
132
  return @info
138
133
  end
139
134
 
140
-
141
-
135
+ def normalize(text)
136
+ text.gsub(/\ /, '_').gsub(/\./, '').downcase
137
+ end
142
138
 
143
139
  end
144
140
  end
145
-
146
- #Set in Progress : Set Complete
147
- #Auth Type Support :
148
- #Auth Type Enable : Callback :
149
- # : User : NONE MD2 MD5 PASSWORD OEM
150
- # : Operator : NONE MD2 MD5
151
- # : Admin : MD2 MD5
152
- # : OEM :
153
- #IP Address Source : DHCP Address
154
- #IP Address : 192.168.1.41
155
- #Subnet Mask : 255.255.255.0
156
- #MAC Address : 00:17:a4:49:ab:70
157
- #BMC ARP Control : ARP Responses Enabled, Gratuitous ARP Disabled
158
- #Gratituous ARP Intrvl : 0.0 seconds
159
- #Default Gateway IP : 192.168.1.1
160
- #802.1q VLAN ID : Disabled
161
- #802.1q VLAN Priority : 0
162
- #Cipher Suite Priv Max : Not Available
@@ -16,12 +16,20 @@ module Rubyipmi::Ipmitool
16
16
 
17
17
  # Turn on the system
18
18
  def on
19
- command("on")
19
+ if off?
20
+ command("on")
21
+ else
22
+ return true
23
+ end
20
24
  end
21
25
 
22
26
  # Turn off the system
23
27
  def off
24
- command("off")
28
+ if off?
29
+ return true
30
+ else
31
+ command("off")
32
+ end
25
33
  end
26
34
 
27
35
  # Power cycle the system
@@ -68,7 +76,5 @@ module Rubyipmi::Ipmitool
68
76
  status == "off"
69
77
  end
70
78
 
71
-
72
-
73
79
  end
74
80
  end
@@ -8,129 +8,102 @@ module Rubyipmi::Ipmitool
8
8
 
9
9
  def refresh
10
10
  @sensors = nil
11
- sensors
11
+ list
12
12
  end
13
13
 
14
14
  def list
15
- sensors
15
+ @sensors ||= parse(getsensors)
16
16
  end
17
17
 
18
18
  def count
19
- sensors.count
19
+ list.count
20
20
  end
21
21
 
22
22
  def names
23
- sensors.keys
23
+ list.keys
24
24
  end
25
25
 
26
+ # returns a hash of fan sensors where the key is fan name and value is the sensor
26
27
  def fanlist(refreshdata=false)
27
28
  refresh if refreshdata
28
- flist = []
29
- values = sensors.each do |sensor|
30
- match = sensor.first.match(/(fan)_(\d+)/)
31
- next if match.nil?
32
- if match[1] == "fan"
33
- num = (match[2].to_i) -1
34
- flist[num] = sensor.last[:value]
29
+ flist = {}
30
+ list.each do | name,sensor |
31
+ if name =~ /.*fan.*/
32
+ flist[name] = sensor
35
33
  end
36
34
  end
37
- flist
35
+ return flist
38
36
  end
39
37
 
38
+ # returns a hash of sensors where each key is the name of the sensor and the value is the sensor
40
39
  def templist(refreshdata=false)
41
40
  refresh if refreshdata
42
- tlist = []
43
- values = sensors.each do |sensor|
44
- match = sensor.first.match(/(temp)_(\d+)/)
45
- next if match.nil?
46
- if match[1] == "temp"
47
- num = (match[2].to_i) -1
48
- tlist[num] = sensor.last[:value]
41
+ tlist = {}
42
+ list.each do | name , sensor |
43
+ if sensor[:unit] =~ /.*degree.*/ || name =~ /.*temp.*/
44
+ tlist[name] = sensor
49
45
  end
50
46
  end
51
- tlist
47
+ return tlist
52
48
  end
53
49
 
54
-
50
+ def getsensors
51
+ options["cmdargs"] = "sensor"
52
+ value = runcmd
53
+ options.delete_notify("cmdargs")
54
+ @result
55
+ end
55
56
 
56
57
  private
57
58
 
58
- def sensors
59
- @sensors ||= parse(getsensors)
60
- end
61
-
62
59
  def method_missing(method, *args, &block)
63
- if not sensors.has_key?(method.to_s)
60
+ if not list.has_key?(method.to_s)
64
61
  raise NoMethodError
65
62
  else
66
- sensors[method.to_s]
63
+ list[method.to_s]
67
64
  end
68
65
  end
69
66
 
70
- def getsensors
71
- options["cmdargs"] = "sensor"
72
- value = runcmd
73
- options.delete_notify("cmdargs")
74
- @result
75
- end
76
-
77
67
  def parse(data)
78
68
  sensorlist = {}
79
- data.lines.each do | line|
80
- # skip the header
81
- data = line.split(/\|/)
82
- sensor = Sensor.new(data.first.strip)
83
- sensor[:value] = data[1].strip
84
- sensor[:unit] = data[2].strip
85
- sensor[:status] = data[3].strip
86
- sensor[:type] = nil
87
- sensor[:state] = nil
88
- #sensor[:lower_nonrec] = data[4].strip
89
- #sensor[:lower_crit] = data[5].strip
90
- #sensor[:lower_noncrit] = data[6].strip
91
- #sensor[:upper_noncrit] = data[7].strip
92
- #sensor[:upper_crit] = data[8].strip
93
- #sensor[:upper_nonrec] = data[9].strip
94
- sensorlist[sensor[:name]] = sensor
95
-
69
+ if ! data.nil?
70
+ data.lines.each do | line|
71
+ # skip the header
72
+ sensor = Sensor.new(line)
73
+ sensorlist[sensor[:name]] = sensor
74
+ end
96
75
  end
97
76
  return sensorlist
98
-
99
77
  end
100
-
101
78
  end
102
79
 
103
- class Sensor < Hash
104
80
 
105
- def initialize(sname)
106
- self[:fullname] = sname
107
- self[:name] = sname.gsub(/\ /, '_').gsub(/\./, '').downcase
81
+ class Sensor < Hash
82
+ def initialize(line)
83
+ parse(line)
84
+ self[:name] = normalize(self[:name])
108
85
  end
109
86
 
110
- #def refresh
111
- # data = "sensor get \"#{self[:fullname]}\" "
112
- # parse(data)
113
- #end
114
-
115
- #def parse(data)
116
- # values = data.lines.collect do |line|
117
- # line.split(':').last.strip
118
- # end
119
- # # first 4 entries are lines we don't care about
120
- # value = values[4].split(/\([\w\W]+\)/)
121
- # self[:value] = value.first.strip
122
- # self[:unit] = value.last.strip
123
- # self[:status] = values[5].strip.chomp
124
- # self[:lower_nonrec] = values[6].strip.chomp
125
- # self[:lower_crit] = values[7].strip.chomp
126
- # self[:lower_noncrit] = values[8].strip.chomp
127
- # self[:upper_noncrit] = values[9].strip.chomp
128
- # self[:upper_crit] = values[10].strip.chomp
129
- # self[:upper_nonrec] = values[11].strip.chomp
130
-
131
-
132
- #end
87
+ private
88
+ def normalize(text)
89
+ text.gsub(/\ /, '_').gsub(/\./, '').downcase
90
+ end
133
91
 
92
+ # Parse the individual sensor
93
+ # Note: not all fields will exist on every server
94
+ def parse(line)
95
+ fields = [:name, :value, :unit, :status, :type, :state, :lower_nonrec,
96
+ :lower_crit,:lower_noncrit, :upper_crit, :upper_nonrec, :asserts_enabled, :deasserts_enabled ]
97
+ # skip the header
98
+ data = line.split(/\|/)
99
+ # should we ever encounter a field not in the fields list, just use a counter based fieldname
100
+ i = 0
101
+ data.each do | value |
102
+ field ||= fields.shift || "field#{i}"
103
+ self[field] = value.strip
104
+ i = i.next
105
+ end
106
+ end
134
107
  end
135
108
 
136
109
  end
@@ -12,10 +12,12 @@ module Rubyipmi
12
12
 
13
13
  class Connection
14
14
 
15
- attr_accessor :options
15
+ attr_accessor :options, :debug
16
+ attr_reader :debug
16
17
 
17
18
 
18
- def initialize(user, pass, host)
19
+ def initialize(user, pass, host,debug_value=false)
20
+ @debug = debug_value
19
21
  @options = Rubyipmi::ObservableHash.new
20
22
  raise("Must provide a host to connect to") unless host
21
23
  @options["H"] = host
@@ -25,7 +27,7 @@ module Rubyipmi
25
27
  @options["P"] = pass if pass
26
28
  # default to IPMI 2.0 communication, this means that older devices will not work
27
29
  # Those old servers should be recycled by now, as the 1.0, 1.5 spec came out in 2005ish and is 2013.
28
- @options["I"] = "lanplus"
30
+ #@options["I"] = "lanplus"
29
31
 
30
32
  #getWorkArounds
31
33
  end
@@ -50,6 +52,20 @@ module Rubyipmi
50
52
  @chassis ||= Rubyipmi::Ipmitool::Chassis.new(@options)
51
53
  end
52
54
 
55
+ def get_diag
56
+ data = {}
57
+ data['provider'] = provider
58
+ if @fru
59
+ data['frus'] = @fru.getfrus
60
+ end
61
+ if @sensors
62
+ data['sensors'] = @sensors.getsensors
63
+ end
64
+ if @bmc
65
+ data['bmc_info'] = @bmc.info
66
+ end
67
+ end
68
+
53
69
  end
54
70
  end
55
71
  end