rubyipmi 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -8
  3. data/README.md +92 -27
  4. data/Rakefile +1 -6
  5. data/VERSION +1 -1
  6. data/lib/rubyipmi.rb +69 -30
  7. data/lib/rubyipmi/commands/basecommand.rb +16 -18
  8. data/lib/rubyipmi/freeipmi/commands/basecommand.rb +2 -4
  9. data/lib/rubyipmi/freeipmi/commands/bmc.rb +7 -0
  10. data/lib/rubyipmi/freeipmi/commands/bmcconfig.rb +10 -0
  11. data/lib/rubyipmi/freeipmi/commands/bmcdevice.rb +1 -0
  12. data/lib/rubyipmi/freeipmi/commands/bmcinfo.rb +0 -3
  13. data/lib/rubyipmi/freeipmi/commands/chassis.rb +1 -0
  14. data/lib/rubyipmi/freeipmi/commands/chassisconfig.rb +0 -2
  15. data/lib/rubyipmi/freeipmi/commands/fru.rb +0 -1
  16. data/lib/rubyipmi/freeipmi/commands/lan.rb +22 -23
  17. data/lib/rubyipmi/freeipmi/commands/sensors.rb +8 -7
  18. data/lib/rubyipmi/freeipmi/connection.rb +14 -19
  19. data/lib/rubyipmi/freeipmi/errorcodes.rb +0 -1
  20. data/lib/rubyipmi/ipmitool/commands/basecommand.rb +0 -3
  21. data/lib/rubyipmi/ipmitool/commands/bmc.rb +8 -0
  22. data/lib/rubyipmi/ipmitool/commands/chassis.rb +1 -0
  23. data/lib/rubyipmi/ipmitool/commands/fru.rb +0 -7
  24. data/lib/rubyipmi/ipmitool/connection.rb +12 -13
  25. data/lib/rubyipmi/ipmitool/errorcodes.rb +2 -1
  26. data/rubyipmi.gemspec +21 -14
  27. data/spec/integration/bmc_spec.rb +9 -10
  28. data/spec/integration/chassis_config_spec.rb +6 -8
  29. data/spec/integration/chassis_spec.rb +3 -3
  30. data/spec/integration/connection_spec.rb +16 -15
  31. data/spec/integration/fru_spec.rb +6 -7
  32. data/spec/integration/lan_spec.rb +21 -34
  33. data/spec/integration/power_spec.rb +5 -5
  34. data/spec/integration/rubyipmi_spec.rb +63 -9
  35. data/spec/integration/sensor_spec.rb +7 -8
  36. data/spec/spec_helper.rb +10 -7
  37. data/spec/unit/freeipmi/bmc-info_spec.rb +5 -6
  38. data/spec/unit/freeipmi/bmc_spec.rb +8 -9
  39. data/spec/unit/freeipmi/connection_spec.rb +41 -23
  40. data/spec/unit/freeipmi/errorcodes_spec.rb +4 -10
  41. data/spec/unit/freeipmi/fru_spec.rb +15 -16
  42. data/spec/unit/freeipmi/sensors_spec.rb +17 -15
  43. data/spec/unit/ipmitool/bmc_spec.rb +11 -12
  44. data/spec/unit/ipmitool/connection_spec.rb +43 -21
  45. data/spec/unit/ipmitool/errorcodes_spec.rb +5 -4
  46. data/spec/unit/ipmitool/fru_spec.rb +15 -15
  47. data/spec/unit/ipmitool/lan_spec.rb +16 -15
  48. data/spec/unit/ipmitool/sensors_spec.rb +16 -15
  49. data/spec/unit/rubyipmi_spec.rb +6 -6
  50. metadata +64 -24
  51. data/README.rdoc +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e4d19bb30d3eeb5fd8777b9bb46b6e6e9b4bfa2c
4
- data.tar.gz: 4c200d37a6b4764a6e6c5eac32fea5b2abb6f01d
3
+ metadata.gz: d461e3d295c4e31dfe971e6c9283158abe3cb9ac
4
+ data.tar.gz: 685a0f016ab45c40be2de1ded13da863bdba4cfb
5
5
  SHA512:
6
- metadata.gz: 4fddc56cd48d76ece1d6daa4a137c05c99122d8605fea92a0253ae20cfddbccafeef504aef6964454daa6b870e35ec703598a5aa893d8926c8fdf680051e9698
7
- data.tar.gz: ded7e2190931753455dd40a7814f40f619c06da4dcaa2550971b218f92ac3375401120fe620cd6e21bdb3961672aa47ddd440c1f3296869f9f13617cebce66f9
6
+ metadata.gz: 9dd16183f0bb968cee9043a5323a29215d1d5a0b317ac9531e859a7f68729aa647cd2016f5424fcee33b17bf3a346ef048d09a7e5e029cf63d7831117093551b
7
+ data.tar.gz: ab8ea8f08702fcda75e79bb02dfd7970f0ce717aa51839bfeeab478df4a6c7e49bab5cfb7d63778d5e0a7eb7d12b42057f290f35c245e500c6d97d6ba5c84ce0
data/Gemfile CHANGED
@@ -1,16 +1,13 @@
1
1
  source "http://rubygems.org"
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
5
2
 
6
- # Add dependencies to develop your gem here.
7
- # Include everything needed to run rake, tests, features, etc.
8
3
  group :development do
9
- gem "rspec", "<= 2.8.0"
4
+ gem "rspec", "~> 3.1"
10
5
  gem "rdoc", "~> 3.12"
11
6
  gem "bundler", ">= 1.1.5"
12
- gem "jeweler", "~> 1.8.4"
13
- # gem "rcov", "< 1.0.0"
7
+ gem "jeweler", "~> 2.0.1"
14
8
  gem "highline"
15
9
  gem "rake"
10
+ gem 'coveralls', require: false
11
+ gem 'pry'
12
+ gem 'pry-rescue'
16
13
  end
data/README.md CHANGED
@@ -1,29 +1,29 @@
1
- # rubyipmi
1
+ # Rubyipmi
2
2
  This gem is a ruby wrapper for the freeipmi and ipmitool command line tools.
3
3
  It provides a ruby implementation of ipmi commands that will make it simple to connect to BMC devices from ruby.
4
4
 
5
5
  [![Build Status](https://travis-ci.org/logicminds/rubyipmi.png)](https://travis-ci.org/logicminds/rubyipmi)
6
6
  [![Gem Version](https://badge.fury.io/rb/rubyipmi.png)](http://badge.fury.io/rb/rubyipmi)
7
- ## Using the library in your code
8
-
9
- ### Install
7
+ [![Coverage Status](https://coveralls.io/repos/logicminds/rubyipmi/badge.png)](https://coveralls.io/r/logicminds/rubyipmi)
10
8
 
9
+ ## Projects that use Rubyipmi
10
+ * https://github.com/sensu/sensu-community-plugins/blob/master/plugins/ipmi/check-sensor.rb
11
+ * https://github.com/theforeman/smart-proxy
12
+ * https://github.com/logicminds/ipmispec
11
13
 
12
- 1. Install the freeipmi from source (http://www.gnu.org/software/freeipmi/) or ipmitool
13
- 2. gem install rubyipmi
14
+ Don't see your project listed? Create a PR with your project listed here.
15
+ ## Using the library in your code
14
16
 
15
- ### General Usage
17
+ ### Requirements
16
18
 
17
- ```Ruby
18
19
 
19
- require 'rubyipmi'
20
-
21
- ```
20
+ 1. Install the freeipmi from source (http://www.gnu.org/software/freeipmi/) or ipmitool
21
+ 2. `gem install rubyipmi`
22
22
 
23
23
  #### Create a connection object
24
24
 
25
- ```Ruby
26
-
25
+ ```ruby
26
+ require 'rubyipmi'
27
27
  conn = Rubyipmi.connect("username", "password", "hostname", "providertype")
28
28
 
29
29
  ```
@@ -34,11 +34,29 @@ It provides a ruby implementation of ipmi commands that will make it simple to c
34
34
  is installed and load the first tool found. If you specify the provider type rubyipmi will only use that specific
35
35
  provider.
36
36
 
37
+ Additionally, if your using [openipmi](http://openipmi.sourceforge.net) and will be using rubyipmi to connect to the
38
+ localhost you can utilize the openipmi driver and not have to pass in any connection parameters. Openipmi works
39
+ by installing a driver and makes it available to the host. Freeipmi/Ipmitool will then try to use this driver to
40
+ automatically use the openipmi if no host is given. The one caveat here is that you cannot control remote hosts using
41
+ openipmi. The rubyipmi code must be executed on the host you want to control. The upside is that you don't need
42
+ any credentials. Some commands may require root privileges to run when using openipmi.
37
43
 
38
- #### Use power functions (not all listed)
44
+ ```ruby
45
+ conn = Rubyipmi.connect
46
+ conn.power.status
47
+ ```
48
+
49
+ Should you need to specify some additional options or the provider type
50
+ ```ruby
51
+ conn = Rubyipmi.connect(nil,nil,nil, 'freeipmi', {:privilege =>'USER'})
52
+ ```
39
53
 
40
- ```Ruby
41
54
 
55
+ #### Use power functions (not all listed)
56
+
57
+ ```ruby
58
+ require 'rubyipmi'
59
+ conn = Rubyipmi.connect("username", "password", "hostname")
42
60
  conn.chassis.power.on
43
61
  conn.chassis.power.off
44
62
  conn.chassis.power.on?
@@ -49,8 +67,9 @@ It provides a ruby implementation of ipmi commands that will make it simple to c
49
67
 
50
68
  #### Boot to specific device
51
69
 
52
- ```Ruby
53
-
70
+ ```ruby
71
+ require 'rubyipmi'
72
+ conn = Rubyipmi.connect("username", "password", "hostname")
54
73
  conn.chassis.bootpxe(true, false) # reboot after setting, one time boot only - non persistent
55
74
  conn.chassis.bootdisk(false, false) # boot to disk on next reboot, don't reboot automatically
56
75
 
@@ -59,8 +78,9 @@ It provides a ruby implementation of ipmi commands that will make it simple to c
59
78
 
60
79
  #### Sensors
61
80
 
62
- ```Ruby
63
-
81
+ ```ruby
82
+ require 'rubyipmi'
83
+ conn = Rubyipmi.connect("username", "password", "hostname")
64
84
  conn.sensors.names
65
85
  conn.sensors.list
66
86
  conn.sensors.<sensor name>
@@ -69,8 +89,9 @@ It provides a ruby implementation of ipmi commands that will make it simple to c
69
89
 
70
90
  #### Fru
71
91
 
72
- ```Ruby
73
-
92
+ ```ruby
93
+ require 'rubyipmi'
94
+ conn = Rubyipmi.connect("username", "password", "hostname")
74
95
  conn.fru.list
75
96
  conn.fru.serial
76
97
  conn.fru.manufacturer
@@ -113,7 +134,7 @@ Creating a new command is actually quite simple. Follow these steps to wrap a f
113
134
  1. Create a new subclass of BaseCommand
114
135
  2. define the initialize function like so, and pass in the name of the command line tool to the super constructor.
115
136
 
116
- ```Ruby
137
+ ```ruby
117
138
  def initialize(opts = {})
118
139
  @options = opts
119
140
  super("bmc-info", opts)
@@ -121,7 +142,7 @@ Creating a new command is actually quite simple. Follow these steps to wrap a f
121
142
 
122
143
  ```
123
144
 
124
- ```Ruby
145
+ ```ruby
125
146
  def initialize(opts = {})
126
147
  @options = opts
127
148
  super("ipmitool", opts)
@@ -156,7 +177,7 @@ the runcmd command. Failure to do so will add previous options to subsequent ru
156
177
 
157
178
  Example:
158
179
 
159
- ```Ruby
180
+ ```ruby
160
181
  def ledlight(status=false, delay=300)
161
182
  if status
162
183
  if delay <= 0
@@ -185,7 +206,7 @@ To get the results:
185
206
 
186
207
  Example:
187
208
 
188
- ```Ruby
209
+ ```ruby
189
210
 
190
211
  def status
191
212
  value = command("--stat")
@@ -212,7 +233,7 @@ Although its not necessary to implement the command function it may be desirable
212
233
  Additionally, should this gem ever become out of date one could call the command function and pass in any
213
234
  arguments that have not already been implemented in the rest of the class.
214
235
 
215
- ```Ruby
236
+ ```ruby
216
237
 
217
238
  def command(opt)
218
239
  status = runcmd([opt])
@@ -254,7 +275,51 @@ Although its not necessary to implement the command function it may be desirable
254
275
  IPMI is great for a vendor neutral management interface. However, not all servers are 100% compatible with the specifications.
255
276
  In order to overcome ipmi non-compliance there will be some workarounds built into this library
256
277
 
278
+ ## Troubleshooting
257
279
 
280
+ ### Log files
281
+ Rubyipmi has a built in logging system for debugging purposes. By default logging is disabled. The logger is a class instance
282
+ variable and will stay in memory for as long as your program or interpreter is loaded. In order to enable logging
283
+ you need to do the following.
284
+
285
+ ```ruby
286
+ require 'rubyipmi'
287
+ require 'logger'
288
+ Rubyipmi.log_level = Logger::DEBUG
289
+ ```
290
+ This will create a log file in /tmp/rubyipmi.log which you can use to trace the commands Rubyipmi generates and runs.
291
+
292
+ If you want to setup a custom logger (not required) you can also pass in a logger instance as well.
293
+
294
+ ```ruby
295
+ require 'rubyipmi'
296
+ require 'logger'
297
+ custom_logger = Logger.new('/var/log/rubyipmi_custom.log')
298
+ custom_logger.progname = 'Rubyipmi'
299
+ custom_logger.level = Logger::DEBUG
300
+ Rubyipmi.logger = custom_logger
301
+ ```
302
+
303
+ ### Diagnostics Function
304
+ Running IPMI commands can be frustrating sometimes and with the addition of this library you are bound to find edge
305
+ cases. If you do find an edge case there is a easy function that will generate a diagnostics file that you can
306
+ review and optionally create an issue with for us to work. Without this information its really hard to help because
307
+ every server is different. The following code will generate a file in /tmp/rubyipmi_diag_data.txt that we can use to
308
+ as test cases. Please look over the file for any sensitive data you don't want to share like ip/mac address.
309
+
310
+ ```ruby
311
+ require 'rubyipmi'
312
+ Rubyipmi.get_diag(user, pass, host)
313
+ ```
314
+
315
+ You can couple this with the logger and also generate a log file of all the commands get_diag uses as well.
316
+
317
+ ```ruby
318
+ require 'rubyipmi'
319
+ require 'logger'
320
+ Rubyipmi.log_level = Logger::DEBUG
321
+ Rubyipmi.get_diag(user, pass, host)
322
+ ```
258
323
 
259
324
  ## Contributing to rubyipmi
260
325
 
@@ -268,7 +333,7 @@ In order to overcome ipmi non-compliance there will be some workarounds built in
268
333
 
269
334
  ## Copyright
270
335
 
271
- Copyright (c) 2012 Corey Osman. See LICENSE.txt for
336
+ Copyright (c) 2015 Corey Osman. See LICENSE.txt for
272
337
  further details.
273
338
 
274
339
 
data/Rakefile CHANGED
@@ -19,7 +19,7 @@ Jeweler::Tasks.new do |gem|
19
19
  # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
20
20
  gem.name = "rubyipmi"
21
21
  gem.homepage = "http://github.com/logicminds/rubyipmi"
22
- gem.license = "GPLv3"
22
+ gem.license = "LGPLv2.1"
23
23
  gem.summary = %Q{A ruby wrapper for ipmi command line tools that supports ipmitool and freeipmi}
24
24
  gem.description = %Q{Provides a library for controlling IPMI devices using pure ruby code}
25
25
  gem.email = "corey@logicminds.biz"
@@ -66,11 +66,6 @@ RSpec::Core::RakeTask.new :integration do |spec|
66
66
  end
67
67
  end
68
68
 
69
- RSpec::Core::RakeTask.new(:rcov) do |spec|
70
- spec.pattern = 'spec/**/*_spec.rb'
71
- spec.rcov = true
72
- end
73
-
74
69
  task :default => :unit
75
70
 
76
71
  require 'rdoc/task'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.1
1
+ 0.9.0
@@ -19,38 +19,79 @@
19
19
 
20
20
  require 'rubyipmi/ipmitool/connection'
21
21
  require 'rubyipmi/freeipmi/connection'
22
+ require 'logger'
22
23
 
24
+ class NullLogger < Logger
25
+ def initialize(*args)
26
+ end
27
+
28
+ def add(*args, &block)
29
+ end
30
+ end
23
31
 
24
32
  module Rubyipmi
25
33
  PRIV_TYPES = ['CALLBACK', 'USER', 'OPERATOR', 'ADMINISTRATOR']
34
+ attr_accessor :logger, :log_level
35
+
36
+ # set a logger instance yourself to customize where the logs should go
37
+ # you will need to set the log level yourself
38
+ def self.logger=(log)
39
+ @logger = log
40
+ end
41
+
42
+ # sets the log level, this should be called first if logging to a file is desired
43
+ # if you wish to customize the logging options, set the logger yourself with logger=
44
+ # valid levels are of the type Logger::INFO, Logger::DEBUG, Logger::ERROR, ...
45
+ def self.log_level=(level)
46
+ @log_level = level
47
+ end
48
+
49
+ # this is an read only method that only creates a real logger if the log_level is set
50
+ # if the log_level is not setup it creates a null logger which logs nothing
51
+ def self.logger
52
+ # by default the log will be set to info
53
+ unless @logger
54
+ if @log_level and @log_level >= 0
55
+ @logger = Logger.new('/tmp/rubyipmi.log')
56
+ @logger.progname = 'Rubyipmi'
57
+ @logger.level = @log_level
58
+ else
59
+ @logger = NullLogger.new
60
+ end
61
+ end
62
+ @logger
63
+ end
26
64
 
27
65
  def self.valid_drivers
28
66
  ['auto', "lan15", "lan20", "open"]
29
67
  end
30
68
 
69
+ def self.valid_providers
70
+ ['auto', 'ipmitool', 'freeipmi']
71
+ end
31
72
  # The connect method will create a connection object based the provider type passed in
32
73
  # If provider is left blank the function will use the first available provider
33
-
34
- def self.connect(user, pass, host, provider='any', opts={:driver => 'auto',
35
- :timeout => 'default', :debug => false})
36
-
74
+ # When the driver is set to auto, rubyipmi will try and figure out which driver to use by common error messages. We will most likely be using
75
+ # the lan20 driver, but in order to support a wide use case we default to auto.
76
+ def self.connect(user, pass, host, provider='any', opts={:driver => 'auto', :timeout => 'default'})
37
77
  # use this variable to reduce cmd calls
38
78
  installed = false
39
79
 
80
+ # allow the user to specify an options hash instead of the provider
81
+ # in the future I would stop using the provider and use the opts hash instead to get the provider
82
+ # This allows us to be a little more flexible if the user is doesn't supply us what we need.
40
83
  if provider.is_a?(Hash)
41
84
  opts = provider
42
- provider = 'any'
85
+ provider = opts[:provider] ||= 'any'
43
86
  end
44
87
 
45
88
  # Verify options just in case user passed in a incomplete hash
46
89
  opts[:driver] ||= 'auto'
47
90
  opts[:timeout] ||= 'default'
48
- opts[:debug] = false if opts[:debug] != true
49
91
 
50
- if ! opts[:privilege].nil?
51
- if ! supported_privilege_type?(opts[:privilege])
52
- raise "Invalid privilege type :#{opts[:privilege]}, must be one of: #{PRIV_TYPES.join("\n")}"
53
- end
92
+ if opts[:privilege] and not supported_privilege_type?(opts[:privilege])
93
+ logger.error("Invalid privilege type :#{opts[:privilege]}, must be one of: #{PRIV_TYPES.join("\n")}") if logger
94
+ raise "Invalid privilege type :#{opts[:privilege]}, must be one of: #{PRIV_TYPES.join("\n")}"
54
95
  end
55
96
 
56
97
  # use the first available provider
@@ -62,6 +103,7 @@ module Rubyipmi
62
103
  provider = "ipmitool"
63
104
  installed = true
64
105
  else
106
+ logger.error("No IPMI provider is installed, please install freeipmi or ipmitool")
65
107
  raise "No IPMI provider is installed, please install freeipmi or ipmitool"
66
108
  end
67
109
  end
@@ -69,22 +111,24 @@ module Rubyipmi
69
111
  # Support multiple drivers
70
112
  # Note: these are just generic names of drivers that need to be specified for each provider
71
113
  unless valid_drivers.include?(opts[:driver])
114
+ logger.debug("You must specify a valid driver: #{valid_drivers.join(',')}") if logger
72
115
  raise "You must specify a valid driver: #{valid_drivers.join(',')}"
73
116
  end
74
117
 
75
118
  # If the provider is available create a connection object
76
119
  if installed or is_provider_installed?(provider)
77
120
  if provider == "freeipmi"
78
- @conn = Rubyipmi::Freeipmi::Connection.new(user, pass, host, opts)
121
+ Rubyipmi::Freeipmi::Connection.new(user, pass, host, opts)
79
122
  elsif provider == "ipmitool"
80
- @conn = Rubyipmi::Ipmitool::Connection.new(user,pass,host, opts)
123
+ Rubyipmi::Ipmitool::Connection.new(user,pass,host, opts)
81
124
  else
82
- raise "Incorrect provider given, must use freeipmi or ipmitool"
125
+ logger.error("Incorrect provider given, must use one of #{valid_providers.join(', ')}") if logger
126
+ raise "Incorrect provider given, must use one of #{valid_providers.join(', ')}"
83
127
  end
84
128
  else
85
129
  # Can't find the provider command line tool, maybe try other provider?
130
+ logger.error("The IPMI provider: #{provider} is not installed") if logger
86
131
  raise "The IPMI provider: #{provider} is not installed"
87
-
88
132
  end
89
133
  end
90
134
 
@@ -93,18 +137,13 @@ module Rubyipmi
93
137
  PRIV_TYPES.include?(type)
94
138
  end
95
139
 
96
- def self.connection
97
- return @conn if @conn
98
- raise "No Connection available, please use the connect method"
99
- end
100
-
101
140
  # method used to find the command which also makes it easier to mock with
102
141
  def self.locate_command(commandname)
103
142
  location = `which #{commandname}`.strip
104
143
  if not $?.success?
105
144
  location = nil
106
145
  end
107
- return location
146
+ location
108
147
  end
109
148
 
110
149
  # Return true or false if the provider is available
@@ -115,6 +154,7 @@ module Rubyipmi
115
154
  when "ipmitool"
116
155
  cmdpath = locate_command('ipmitool')
117
156
  else
157
+ logger.error("Invalid BMC provider type") if logger
118
158
  raise "Invalid BMC provider type"
119
159
  end
120
160
  # return false if command was not found
@@ -141,24 +181,23 @@ module Rubyipmi
141
181
  end
142
182
 
143
183
  # gets data from the bmc device and puts in a hash for diagnostics
144
- def self.get_diag(user, pass, host)
184
+ def self.get_diag(user, pass, host, opts={:driver => 'auto', :timeout => 'default'})
145
185
  data = {}
146
-
147
186
  if Rubyipmi.is_provider_installed?('freeipmi')
148
- @freeconn = Rubyipmi::connect(user, pass, host, 'freeipmi')
149
- if @freeconn
187
+ freeconn = Rubyipmi.connect(user, pass, host, 'freeipmi', opts)
188
+ if freeconn
150
189
  puts "Retrieving freeipmi data"
151
- data['freeipmi'] = @freeconn.get_diag
190
+ data[:freeipmi] = freeconn.get_diag
152
191
  end
153
192
  end
154
193
  if Rubyipmi.is_provider_installed?('ipmitool')
155
- @ipmiconn = Rubyipmi::connect(user, pass, host, 'ipmitool')
156
- if @ipmiconn
194
+ ipmiconn = Rubyipmi.connect(user, pass, host, 'ipmitool', opts)
195
+ if ipmiconn
157
196
  puts "Retrieving ipmitool data"
158
- data['ipmitool'] = @ipmiconn.get_diag
197
+ data[:ipmitool] = ipmiconn.get_diag
159
198
  end
160
199
  end
161
- return data
200
+ File.open('/tmp/rubyipmi_diag_data.txt', 'w') {|f| f.write(data)}
201
+ puts "Created file /tmp/rubyipmi_diag_data.txt"
162
202
  end
163
-
164
203
  end