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
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NTk3MjAzNzllY2Y0NWY0Y2RhNzc3MTFkZWZkYTdkY2M4ZjAxOGI5Nw==
5
+ data.tar.gz: !binary |-
6
+ MGY3MWY0ZDVlZmNiYmE1YTg2YzY1YzY0ODY3N2ZiMmFiZjM5YzdjMQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NDdiYmRlMjI3NjQ0Y2E3YmRkMTVmMmQzMDhkZmE0MTQwM2NkNGVjMTY0ODM2
10
+ M2Q1NzAwYzljZTdlYTE1NzU2ZjQ3NGUwZmI3NjdkMGE4MDNhZjNjY2UwNWRh
11
+ NGVlMjU5Mzc5NDRiODBkYjU4MWQxMjgyZDE0NWE2NzRmNmUyYjU=
12
+ data.tar.gz: !binary |-
13
+ N2YwMjM5YjI4NjhiNmY5ZmI1ZGRkYWIwNzZjMGY3NDQ0YjQwMGE2ZTUyYWIz
14
+ YTM5ODZlY2VhYjE2NzRjYjA3NDUxYzc1MzY1MjRlYmViOTA2OGUzZmUxOGMy
15
+ ODYxZGQ5ZjU0ZDBmMDEyMGI1NmNhYzAwYzc1YmIwNDczOGYxYzQ=
data/Gemfile CHANGED
@@ -6,9 +6,11 @@ source "http://rubygems.org"
6
6
  # Add dependencies to develop your gem here.
7
7
  # Include everything needed to run rake, tests, features, etc.
8
8
  group :development do
9
- gem "rspec", "~> 2.8.0"
9
+ gem "rspec", "<= 2.8.0"
10
10
  gem "rdoc", "~> 3.12"
11
- gem "bundler", "~> 1.1.5"
11
+ gem "bundler", ">= 1.1.5"
12
12
  gem "jeweler", "~> 1.8.4"
13
- gem "rcov", ">= 0"
13
+ gem "rcov", "< 1.0.0"
14
+ gem "highline"
15
+ gem "rake"
14
16
  end
data/README.md CHANGED
@@ -2,6 +2,8 @@
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
+ [![Build Status](https://travis-ci.org/logicminds/rubyipmi.png)](https://travis-ci.org/logicminds/rubyipmi)
6
+
5
7
  ## Using the library in your code
6
8
 
7
9
  ### Install
@@ -12,10 +14,10 @@ It provides a ruby implementation of ipmi commands that will make it simple to c
12
14
 
13
15
  ### General Usage
14
16
 
15
- ` require 'rubyipmi' `
17
+ ``` require 'rubyipmi' ```
16
18
 
17
19
  #### Create a connection object
18
- `conn = Rubyipmi.connect("username", "password", "hostname", "providertype) `
20
+ ```conn = Rubyipmi.connect("username", "password", "hostname", "providertype) ```
19
21
 
20
22
  Providertype: optional (ipmitool or freeipmi)
21
23
 
@@ -25,38 +27,38 @@ It provides a ruby implementation of ipmi commands that will make it simple to c
25
27
 
26
28
 
27
29
  #### Use power functions (not all listed)
28
- `
30
+ ```
29
31
  conn.chassis.power.on
30
32
  conn.chassis.power.off
31
33
  conn.chassis.power.on?
32
34
  conn.chassis.power.off?
33
35
  conn.chassis.power.cycle
34
- `
36
+ ```
35
37
 
36
38
  #### Boot to specific device
37
- `
39
+ ```
38
40
  conn.chassis.bootpxe(true, false) # reboot after setting, one time boot only - non persistent
39
41
  conn.chassis.bootdisk(false, false) # boot to disk on next reboot, don't reboot automatically
40
42
 
41
- `
43
+ ```
42
44
 
43
45
 
44
46
  #### Sensors
45
- `
47
+ ```
46
48
  conn.sensors.names
47
49
  conn.sensors.list
48
50
  conn.sensors.<sensor name>
49
51
 
50
- `
52
+ ```
51
53
 
52
54
  #### Fru
53
- `
55
+ ```
54
56
  conn.fru.list
55
57
  conn.fru.serial
56
58
  conn.fru.manufacturer
57
59
  conn.fru.product
58
60
 
59
- `
61
+ ```
60
62
 
61
63
  ## Testing
62
64
  There are a series of automated rspec tests that test the functionality of this library with the ipmi device.
@@ -67,7 +69,8 @@ DO NOT PERFORM THESE TEST ON ANY PRODUCTION SYSTEM. THESE TESTS WILL TURN OFF T
67
69
 
68
70
  1. Install gem via source
69
71
  2. bundle install
70
- 3. rake ipmiuser=ipmiuser ipmipass=ipmiuserpass ipmihost=192.168.1.22 ipmiprovider=freeipmi (fill in your your details)
72
+ 3. rake (runs unit tests, does not require a ipmi device)
73
+ 3. rake integration ipmiuser=ipmiuser ipmipass=ipmiuserpass ipmihost=192.168.1.22 ipmiprovider=freeipmi (fill in your your details)
71
74
  4. report any failures with your make/model/firmware revision to corey@logicminds.biz
72
75
 
73
76
  ## Security
@@ -155,14 +158,21 @@ end
155
158
  ```
156
159
 
157
160
  ### How to get the results of the command
158
- After running a command it may be desirable to get the results for further processing. To get the results, follow the example below:
161
+ After running a command it may be desirable to get the results for further processing.
162
+ Note that there are two kinds of results.
163
+ 1. the text returned from the shell command, this is stored in @results
164
+ 2. the status value returned from the shell command (true or false only) this is returned from runcmd.
165
+
166
+ To get the results:
159
167
 
160
168
  Example:
161
169
 
162
170
  ```
163
171
  def status
164
- command("--stat")
165
- @result.split(":").last.chomp.trim
172
+ value = command("--stat")
173
+ if value == true
174
+ @result.split(":").last.chomp.trim
175
+ end
166
176
  end
167
177
 
168
178
  def command(opt)
data/Rakefile CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'bundler'
5
+ @base_dir = File.dirname(__FILE__)
6
+
7
+
5
8
  begin
6
9
  Bundler.setup(:default, :development)
7
10
  rescue Bundler::BundlerError => e
@@ -18,17 +21,49 @@ Jeweler::Tasks.new do |gem|
18
21
  gem.homepage = "http://github.com/logicminds/rubyipmi"
19
22
  gem.license = "GPLv3"
20
23
  gem.summary = %Q{A ruby wrapper for ipmi command line tools that supports ipmitool and freeipmi}
21
- gem.description = %Q{A ruby wrapper for ipmi command line tools that supports ipmitool and freeipmi}
24
+ gem.description = %Q{Provides a library for controlling IPMI devices using pure ruby code}
22
25
  gem.email = "corey@logicminds.biz"
23
26
  gem.authors = ["Corey Osman"]
27
+ gem.files.exclude '.travis.yml'
28
+ gem.files.exclude 'Gemfile.lock'
29
+ gem.files.exclude '.rspec'
30
+ gem.files.exclude '.gitignore'
31
+ gem.files.exclude '.document'
32
+ gem.files.exclude 'coverage/'
33
+
34
+
24
35
  # dependencies defined in Gemfile
25
36
  end
26
37
  Jeweler::RubygemsDotOrgTasks.new
27
38
 
28
39
  require 'rspec/core'
29
40
  require 'rspec/core/rake_task'
30
- RSpec::Core::RakeTask.new(:spec) do |spec|
31
- spec.pattern = FileList['spec/**/*_spec.rb']
41
+
42
+ desc "run unit tests"
43
+ RSpec::Core::RakeTask.new(:unit) do |spec|
44
+ spec.pattern = FileList['spec/unit/**/*_spec.rb']
45
+ end
46
+
47
+ desc "Run integrations tests against real systems using a vagrant box"
48
+ task :vintegration, :user, :pass, :host do |task, args|
49
+ vars = "ipmiuser=#{args[:user]} ipmipass=#{args[:pass]} ipmihost=#{args[:host]}"
50
+ ipmiprovider="freeipmi"
51
+ puts `cd #{@base_dir}/spec && vagrant up`
52
+ puts `cd #{@base_dir}/spec && vagrant provision`
53
+ puts `vagrant ssh \"/rubyipmi/rake integration #{vars}\"`
54
+ end
55
+
56
+ desc "Run integrations tests against real systems"
57
+ RSpec::Core::RakeTask.new :integration do |spec|
58
+ ENV['ipmiuser'] = 'admin'
59
+ ENV['ipmipass'] = 'password'
60
+ ENV['ipmihost'] = '10.0.1.16'
61
+ providers ||= ENV['ipmiprovider'].to_a || ['freeipmi', 'ipmitool']
62
+
63
+ providers.each do | provider |
64
+ ENV['ipmiprovider'] = provider
65
+ spec.pattern = FileList['spec/integration/**/*_spec.rb']
66
+ end
32
67
  end
33
68
 
34
69
  RSpec::Core::RakeTask.new(:rcov) do |spec|
@@ -36,7 +71,7 @@ RSpec::Core::RakeTask.new(:rcov) do |spec|
36
71
  spec.rcov = true
37
72
  end
38
73
 
39
- task :default => :spec
74
+ task :default => :unit
40
75
 
41
76
  require 'rdoc/task'
42
77
  Rake::RDocTask.new do |rdoc|
@@ -47,3 +82,46 @@ Rake::RDocTask.new do |rdoc|
47
82
  rdoc.rdoc_files.include('README*')
48
83
  rdoc.rdoc_files.include('lib/**/*.rb')
49
84
  end
85
+
86
+ desc "send diagnostics to logicminds for testing for the given host"
87
+ task :send_diag, :user, :pass, :host do |t, args |
88
+ require 'rubyipmi'
89
+ require 'net/smtp'
90
+ require 'json'
91
+ require "highline/import"
92
+
93
+ if args.count < 3
94
+ raise "You must provide arguments: rake send_diag[user, pass, host]"
95
+ end
96
+ data = Rubyipmi.get_diag(args[:user], args[:pass], args[:host])
97
+ emailto = 'corey@logicminds.biz'
98
+ subject = "Rubyipmi diagnostics data"
99
+ send_email(emailto, data.to_json, {:subject => subject})
100
+
101
+ end
102
+
103
+ def send_email(to,data, opts={})
104
+ gmail_id = ask("Enter your gmail account: ")
105
+ pass = ask("Enter your gmail password: ") { |q| q.echo = '*' }
106
+ opts[:from] = gmail_id
107
+ opts[:server] ||= 'smtp.gmail.com'
108
+ opts[:from_alias] ||= gmail_id
109
+ opts[:subject] ||= @subject
110
+ opts[:body] ||= data
111
+ opts[:to] ||= to
112
+ opts[:port] ||= 587
113
+ msg = <<END_OF_MESSAGE
114
+ From: #{opts[:from_alias]} <#{opts[:from]}>
115
+ To: <#{to}>
116
+ Subject: #{opts[:subject]}
117
+ Date: #{Time.now.rfc2822}
118
+
119
+ #{opts[:body]}
120
+ END_OF_MESSAGE
121
+
122
+ smtp = Net::SMTP.new(opts[:server],opts[:port])
123
+ smtp.enable_starttls
124
+ smtp.start(opts[:server],gmail_id,pass,:login) do
125
+ smtp.send_message(msg, gmail_id, to)
126
+ end
127
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0
1
+ 0.7.0
data/lib/rubyipmi.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'rubyipmi/ipmitool/connection'
2
2
  require 'rubyipmi/freeipmi/connection'
3
- require 'net/smtp'
4
3
 
5
4
 
6
5
  module Rubyipmi
@@ -9,7 +8,7 @@ module Rubyipmi
9
8
  # The connect method will create a connection object based the provider type passed in
10
9
  # If provider is left blank the function will use the first available provider
11
10
 
12
- def self.connect(user, pass, host, provider="any")
11
+ def self.connect(user, pass, host, provider="any",debug=false)
13
12
 
14
13
  # use this variable to reduce cmd calls
15
14
  installed = false
@@ -30,9 +29,9 @@ module Rubyipmi
30
29
  # If the provider is available create a connection object
31
30
  if installed or is_provider_installed?(provider)
32
31
  if provider == "freeipmi"
33
- @conn = Rubyipmi::Freeipmi::Connection.new(user, pass, host)
32
+ @conn = Rubyipmi::Freeipmi::Connection.new(user, pass, host, debug)
34
33
  elsif provider == "ipmitool"
35
- @conn = Rubyipmi::Ipmitool::Connection.new(user,pass,host)
34
+ @conn = Rubyipmi::Ipmitool::Connection.new(user,pass,host, debug)
36
35
  else
37
36
  raise "Incorrect provider given, must use freeipmi or ipmitool"
38
37
  end
@@ -48,17 +47,27 @@ module Rubyipmi
48
47
  raise "No Connection available, please use the connect method"
49
48
  end
50
49
 
50
+ # method used to find the command which also makes it easier to mock with
51
+ def self.locate_command(commandname)
52
+ location = `which #{commandname}`.strip
53
+ if not $?.success?
54
+ location = nil
55
+ end
56
+ return location
57
+ end
58
+
51
59
  # Return true or false if the provider is available
52
60
  def self.is_provider_installed?(provider)
53
61
  case provider
54
62
  when "freeipmi"
55
- cmdpath = `which ipmipower`.strip
63
+ cmdpath = locate_command('ipmipower')
56
64
  when "ipmitool"
57
- cmdpath = `which ipmitool`.strip
65
+ cmdpath = locate_command('ipmitool')
58
66
  else
59
67
  raise "Invalid BMC provider type"
60
68
  end
61
- return $?.success?
69
+ # return false if command was not found
70
+ return ! cmdpath.nil?
62
71
  end
63
72
 
64
73
  def self.providers
@@ -80,12 +89,25 @@ module Rubyipmi
80
89
  return available
81
90
  end
82
91
 
83
- def self.printdiag(user, pass, host)
84
- @conn = Rubyipmi::connect(user, pass, host)
85
- puts "Product: #{@conn.fru.product}"
86
- puts "Manufacturer: #{@conn.fru.manufacturer}"
87
- puts "BMC Info #{@conn.bmc.info.inspect}\n"
88
- puts "Please email to corey@logicminds.biz when troubleshooting"
89
- return true
92
+ # gets data from the bmc device and puts in a hash for diagnostics
93
+ def self.get_diag(user, pass, host)
94
+ data = {}
95
+
96
+ if Rubyipmi.is_provider_installed?('freeipmi')
97
+ @freeconn = Rubyipmi::connect(user, pass, host, 'freeipmi')
98
+ if @freeconn
99
+ puts "Retrieving freeipmi data"
100
+ data['freeipmi'] = @freeconn.get_diag
101
+ end
102
+ end
103
+ if Rubyipmi.is_provider_installed?('ipmitool')
104
+ @ipmiconn = Rubyipmi::connect(user, pass, host, 'ipmitool')
105
+ if @ipmiconn
106
+ puts "Retrieving ipmitool data"
107
+ data['ipmitool'] = @ipmiconn.get_diag
108
+ end
109
+ end
110
+ return data
90
111
  end
112
+
91
113
  end
@@ -5,11 +5,9 @@ module Rubyipmi
5
5
 
6
6
  class BaseCommand
7
7
  include Observable
8
-
9
-
10
- attr_reader :cmd
11
- attr_accessor :options
12
- attr_reader :lastcall
8
+ attr_reader :cmd, :max_retry_count
9
+ attr_accessor :options, :passfile
10
+ attr_reader :lastcall, :result
13
11
 
14
12
  def makecommand
15
13
  # override in subclass
@@ -17,170 +15,110 @@ module Rubyipmi
17
15
 
18
16
  def setpass
19
17
  @passfile = Tempfile.new('')
20
- @passfile.open
21
18
  end
22
19
 
23
20
  def removepass
24
- @passfile.close!
21
+ @passfile.unlink
25
22
  end
26
23
 
27
- def to_s
24
+ def dump_command
28
25
  makecommand
29
26
  end
30
27
 
31
28
  def initialize(commandname, opts = ObservableHash.new)
32
29
  # This will locate the command path or raise an error if not found
33
30
  @cmdname = commandname
34
- @cmd = `which #{commandname}`.strip
31
+ @options = opts
32
+ @options.add_observer(self)
33
+ end
34
+
35
+ def locate_command(commandname)
36
+ location = `which #{commandname}`.strip
35
37
  if not $?.success?
36
38
  raise "#{commandname} command not found, is #{commandname} installed?"
37
39
  end
38
- @options = opts
39
- @options.add_observer(self)
40
+ return location
40
41
  end
41
42
 
42
43
  # Use this function to run the command line tool, it will inherently use the options hash for all options
43
44
  # That need to be specified on the command line
44
45
  def runcmd(debug=false)
45
46
  @success = false
46
-
47
- result = catch(:ipmierror){
48
- @success = run(debug)
49
- }
50
- # if error occurs try and find the fix
51
- if result and not @success
52
- findfix(result, nil, debug, "runcmd")
47
+ @success = run(debug)
48
+ if ENV['rubyipmi_debug'] == 'true'
49
+ puts @lastcall.inspect unless @lastcall.nil?
53
50
  end
54
51
  return @success
55
-
56
-
57
52
  end
58
53
 
54
+ def run(debug=false)
55
+ # we search for the command everytime just in case its removed during execution
56
+ # we also don't want to add this to the initialize since mocking is difficult and we don't want to
57
+ # throw errors upon object creation
58
+ retrycount = 0
59
+ process_status = false
60
+ @cmd = locate_command(@cmdname)
61
+ setpass
62
+ @result = nil
63
+ if debug
64
+ # Log error
65
+ return makecommand
66
+ end
59
67
 
60
- def runcmd_without_opts(args=[], debug=false)
61
-
62
- @success = false
63
- result = catch(:ipmierror){
64
- @success = run_without_opts(args, debug)
68
+ begin
69
+ command = makecommand
70
+ @lastcall = "#{command}"
71
+ @result = `#{command} 2>&1`
72
+ # sometimes the command tool does not return the correct result so we have to validate it with additional
73
+ # code
74
+ process_status = validate_status($?)
75
+ rescue
76
+ if retrycount < max_retry_count
77
+ find_fix(@result)
78
+ retrycount = retrycount.next
79
+ retry
80
+ else
81
+ raise "Exhausted all auto fixes, cannot determine what the problem is"
82
+ end
83
+ ensure
84
+ removepass
85
+ return process_status
65
86
 
66
- }
67
- # if error occurs try and find the fix and rerun the method
68
- if result and not @success
69
- findfix(result, args, debug, "runcmd_with_args")
70
87
  end
71
- return @success
88
+
72
89
  end
73
90
 
74
91
  # The findfix method acts like a recursive method and applies fixes defined in the errorcodes
75
92
  # If a fix is found it is applied to the options hash, and then the last run command is retried
76
93
  # until all the fixes are exhausted or a error not defined in the errorcodes is found
77
- def findfix(result, args, debug, runmethod)
94
+ # this must be overrided in the subclass, as there are no generic errors that fit both providers
95
+ def find_fix(result)
78
96
  if result
79
97
  # The errorcode code hash contains the fix
80
- fix = ErrorCodes.code[result]
81
- if not fix
82
- raise "#{result}"
83
- else
98
+ begin
99
+ fix = ErrorCodes.search(result)
84
100
  @options.merge_notify!(fix)
85
- # retry the last called method
86
- # its quicker to explicitly call these commands than calling a command block
87
- if runmethod == "run"
88
- run(debug)
89
- else
90
- run_without_opts(args, debug)
91
- end
92
101
 
102
+ rescue
103
+ raise "Could not find fix for error code: \n#{result}"
93
104
  end
94
-
95
- end
96
- end
97
-
98
-
99
- def run(debug=false)
100
- setpass
101
- @result = nil
102
- command = makecommand
103
- if debug
104
- return command
105
- end
106
-
107
- @lastcall = "#{command}"
108
- @result = `#{command} 2>&1`
109
- removepass
110
- #puts "Last Call: #{@lastcall}"
111
-
112
- # sometimes the command tool doesnt return the correct result
113
- process_status = validate_status($?)
114
-
115
- if not process_status
116
- throwError
117
105
  end
118
- return process_status
119
- end
120
-
121
-
122
-
123
- def run_without_opts(args=[], debug=false)
124
- setpass
125
- @result = ""
126
- if debug
127
- return "#{cmd} #{args.join(" ")}"
128
- else
129
- @lastcall = "#{cmd} #{args.join(" ")}"
130
- @result = `#{cmd} #{args.join(" ")} 2>&1`
131
- removepass
132
- end
133
-
134
- process_status = validate_status($?)
135
-
136
- if not process_status
137
- throwError
138
- end
139
- return process_status
140
-
141
-
142
106
  end
143
107
 
144
108
  def update(opts)
145
109
  @options.merge!(opts)
146
- #puts "Options were updated: #{@options.inspect}"
147
110
  end
148
111
 
149
-
150
-
151
-
152
- # This method will check if the results are really valid as the exit code can be misleading and incorrect
112
+ # This method will check if the results are really valid as the exit code can be misleading and incorrect
153
113
  def validate_status(exitstatus)
154
114
  # override in child class if needed
155
- return exitstatus.success?
156
-
157
- end
158
-
159
- def throwError
160
- # Find out what kind of error is happening, parse results
161
- # Check for authentication or connection issue
162
- #puts "ipmi call: #{@lastcall}"
163
-
164
- if @result =~ /timeout|timed\ out/
165
- code = "ipmi call: #{@lastcall} timed out"
166
- raise code
115
+ if ! exitstatus.success?
116
+ raise "Error occurred"
167
117
  else
168
- code = @result.split(":").last.chomp.strip if not @result.empty?
118
+ return true
169
119
  end
170
- case code
171
- when "invalid hostname"
172
- raise code
173
- when "password invalid"
174
- raise code
175
- when "username invalid"
176
- raise code
177
- else
178
- throw :ipmierror, code
179
- end
180
-
181
120
  end
182
121
 
183
122
 
184
-
185
123
  end
186
124
  end