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
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", "
|
9
|
+
gem "rspec", "<= 2.8.0"
|
10
10
|
gem "rdoc", "~> 3.12"
|
11
|
-
gem "bundler", "
|
11
|
+
gem "bundler", ">= 1.1.5"
|
12
12
|
gem "jeweler", "~> 1.8.4"
|
13
|
-
gem "rcov", "
|
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
|
+
[](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
|
-
|
17
|
+
``` require 'rubyipmi' ```
|
16
18
|
|
17
19
|
#### Create a connection object
|
18
|
-
|
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
|
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.
|
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
|
-
|
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{
|
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
|
-
|
31
|
-
|
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 => :
|
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.
|
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 =
|
63
|
+
cmdpath = locate_command('ipmipower')
|
56
64
|
when "ipmitool"
|
57
|
-
cmdpath =
|
65
|
+
cmdpath = locate_command('ipmitool')
|
58
66
|
else
|
59
67
|
raise "Invalid BMC provider type"
|
60
68
|
end
|
61
|
-
return
|
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
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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 :
|
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.
|
21
|
+
@passfile.unlink
|
25
22
|
end
|
26
23
|
|
27
|
-
def
|
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
|
-
@
|
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
|
-
|
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
|
-
|
48
|
-
@
|
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
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
81
|
-
|
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
|
-
|
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
|
-
|
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
|