rubyipmi 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![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
|
-
|
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
|