rubyipmi 0.3.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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +33 -0
- data/LICENSE.txt +20 -0
- data/README.md +267 -0
- data/README.rdoc +18 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/lib/rubyipmi.rb +80 -0
- data/lib/rubyipmi/commands/basecommand.rb +171 -0
- data/lib/rubyipmi/freeipmi/commands/basecommand.rb +60 -0
- data/lib/rubyipmi/freeipmi/commands/bmc.rb +37 -0
- data/lib/rubyipmi/freeipmi/commands/bmcconfig.rb +57 -0
- data/lib/rubyipmi/freeipmi/commands/bmcinfo.rb +76 -0
- data/lib/rubyipmi/freeipmi/commands/chassis.rb +123 -0
- data/lib/rubyipmi/freeipmi/commands/chassisconfig.rb +100 -0
- data/lib/rubyipmi/freeipmi/commands/lan.rb +111 -0
- data/lib/rubyipmi/freeipmi/commands/power.rb +72 -0
- data/lib/rubyipmi/freeipmi/connection.rb +43 -0
- data/lib/rubyipmi/freeipmi/errorcodes.rb +15 -0
- data/lib/rubyipmi/ipmitool/commands/basecommand.rb +60 -0
- data/lib/rubyipmi/ipmitool/commands/bmc.rb +95 -0
- data/lib/rubyipmi/ipmitool/commands/chassis.rb +106 -0
- data/lib/rubyipmi/ipmitool/commands/chassisconfig.rb +52 -0
- data/lib/rubyipmi/ipmitool/commands/lan.rb +162 -0
- data/lib/rubyipmi/ipmitool/commands/power.rb +74 -0
- data/lib/rubyipmi/ipmitool/connection.rb +46 -0
- data/lib/rubyipmi/ipmitool/errorcodes.rb +18 -0
- data/lib/rubyipmi/observablehash.rb +20 -0
- data/rubyipmi.gemspec +91 -0
- data/spec/bmc_spec.rb +35 -0
- data/spec/chassis_config_spec.rb +38 -0
- data/spec/chassis_spec.rb +24 -0
- data/spec/connection_spec.rb +31 -0
- data/spec/lan_spec.rb +61 -0
- data/spec/power_spec.rb +40 -0
- data/spec/rubyipmi_spec.rb +59 -0
- data/spec/spec_helper.rb +12 -0
- metadata +181 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
module Rubyipmi::Freeipmi
|
2
|
+
|
3
|
+
class ChassisConfig < Rubyipmi::Freeipmi::BaseCommand
|
4
|
+
|
5
|
+
def initialize(opts = ObservableHash.new)
|
6
|
+
super("ipmi-chassis-config", opts)
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
# This is the raw command to send a new configuration to the ipmi device
|
11
|
+
def commit
|
12
|
+
@options["commit"] = false
|
13
|
+
value = runcmd
|
14
|
+
@options.delete_notify("commit")
|
15
|
+
return value
|
16
|
+
end
|
17
|
+
|
18
|
+
# This is the raw command to get the entire ipmi chassis configuration
|
19
|
+
# If you pass in a section you will get just the section
|
20
|
+
def checkout(section=nil)
|
21
|
+
@options["checkout"] = false
|
22
|
+
if section
|
23
|
+
@options["section"] = section
|
24
|
+
end
|
25
|
+
value = runcmd
|
26
|
+
@options.delete_notify("checkout")
|
27
|
+
if section
|
28
|
+
@options.delete_notify("section")
|
29
|
+
end
|
30
|
+
return value
|
31
|
+
end
|
32
|
+
|
33
|
+
def bootdevice
|
34
|
+
value = checkout("Chassis_Boot_Flags")
|
35
|
+
if value
|
36
|
+
# TODO parse result to return current boot device
|
37
|
+
#@result
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def bootdevice(device, persistent=false)
|
42
|
+
setBootFlag("Boot_Device", device)
|
43
|
+
end
|
44
|
+
|
45
|
+
def bootdevices
|
46
|
+
# freeipmi returns a list of supported devices
|
47
|
+
# However, for now we will just assume the following
|
48
|
+
["PXE", "HARD-DRIVE", "CD-DVD", "BIOS-SETUP"]
|
49
|
+
# TODO return array of possible boot devices
|
50
|
+
end
|
51
|
+
|
52
|
+
def bootpersistent(value)
|
53
|
+
# TODO find out if we can specify multiple key-pair values
|
54
|
+
if value == true
|
55
|
+
flag = "Chassis_Boot_Flags:Boot_Flags_Persistent=Yes"
|
56
|
+
else
|
57
|
+
flag = "Chassis_Boot_Flags:Boot_Flags_Persistent=No"
|
58
|
+
end
|
59
|
+
@options["key-pair"] = "\"#{flag}\""
|
60
|
+
value = commit
|
61
|
+
@options.delete_notify("key-pair")
|
62
|
+
return value
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
# shortcut to set boot device to pxe
|
68
|
+
def bootpxe(persistent=false)
|
69
|
+
bootdevice("PXE")
|
70
|
+
end
|
71
|
+
|
72
|
+
# shortcut to set boot device to disk
|
73
|
+
def bootdisk(persistent=false)
|
74
|
+
bootdevice("HARD-DRIVE")
|
75
|
+
end
|
76
|
+
|
77
|
+
# shortcut to set boot device to cdrom
|
78
|
+
def bootcdrom(persistent=false)
|
79
|
+
bootdevice("CD-DVD")
|
80
|
+
end
|
81
|
+
|
82
|
+
# shortcut to boot into bios setup
|
83
|
+
def bootbios(persistent=false)
|
84
|
+
bootdevice("BIOS-SETUP")
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def setBootFlag(key,flag, persistent=false)
|
90
|
+
@options["key-pair"] = "\"Chassis_Boot_Flags:#{key}=#{flag}\""
|
91
|
+
value = commit
|
92
|
+
@options.delete_notify("key-pair")
|
93
|
+
return value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
## Possible values: NO-OVERRIDE/PXE/HARD-DRIVE/HARD-DRIVE-SAFE-MODE/
|
98
|
+
## DIAGNOSTIC_PARTITION/CD-DVD/BIOS-SETUP/REMOTE-FLOPPY
|
99
|
+
## PRIMARY-REMOTE-MEDIA/REMOTE-CD-DVD/REMOTE-HARD-DRIVE/FLOPPY
|
100
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Rubyipmi::Freeipmi
|
2
|
+
|
3
|
+
class Lan
|
4
|
+
|
5
|
+
attr_accessor :info
|
6
|
+
attr_accessor :channel
|
7
|
+
attr_accessor :config
|
8
|
+
|
9
|
+
def initialize(opts)
|
10
|
+
@config = Rubyipmi::Freeipmi::BmcConfig.new(opts)
|
11
|
+
|
12
|
+
@info = {}
|
13
|
+
@channel = 2
|
14
|
+
end
|
15
|
+
|
16
|
+
def info
|
17
|
+
if @info.length < 1
|
18
|
+
parse(@config.section("Lan_Conf"))
|
19
|
+
else
|
20
|
+
@info
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def dhcp?
|
25
|
+
if @info.length < 1
|
26
|
+
parse(@config.section("Lan_Conf"))
|
27
|
+
end
|
28
|
+
@info["ip_address_source"].match(/dhcp/i) != nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def static?
|
32
|
+
if @info.length < 1
|
33
|
+
parse(@config.section("Lan_Conf"))
|
34
|
+
end
|
35
|
+
@info["ip_address_source"].match(/static/i) != nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def ip
|
39
|
+
if @info.length < 1
|
40
|
+
parse(@config.section("Lan_Conf"))
|
41
|
+
end
|
42
|
+
@info["ip_address"]
|
43
|
+
end
|
44
|
+
|
45
|
+
def mac
|
46
|
+
if @info.length < 1
|
47
|
+
parse(@config.section("Lan_Conf"))
|
48
|
+
end
|
49
|
+
@info["mac_address"]
|
50
|
+
end
|
51
|
+
|
52
|
+
def subnet
|
53
|
+
if @info.length < 1
|
54
|
+
parse(@config.section("Lan_Conf"))
|
55
|
+
end
|
56
|
+
@info["subnet_mask"]
|
57
|
+
end
|
58
|
+
|
59
|
+
def gateway
|
60
|
+
if @info.length < 1
|
61
|
+
parse(@config.section("Lan_Conf"))
|
62
|
+
end
|
63
|
+
@info["default_gateway_ip_address"]
|
64
|
+
end
|
65
|
+
|
66
|
+
# def snmp
|
67
|
+
#
|
68
|
+
# end
|
69
|
+
|
70
|
+
# def vlanid
|
71
|
+
#
|
72
|
+
# end
|
73
|
+
|
74
|
+
# def snmp=(community)
|
75
|
+
#
|
76
|
+
# end
|
77
|
+
|
78
|
+
def set_ip(address, static=true)
|
79
|
+
@config.setsection("Lan_Conf", "IP_Address", address)
|
80
|
+
end
|
81
|
+
|
82
|
+
def set_subnet(subnet)
|
83
|
+
@config.setsection("Lan_Conf", "Subnet_Mask", subnet)
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_gateway(address)
|
87
|
+
@config.setsection("Lan_Conf", "Default_Gateway_IP_Address", address)
|
88
|
+
end
|
89
|
+
|
90
|
+
# def vlanid=(vlan)
|
91
|
+
#
|
92
|
+
# end
|
93
|
+
|
94
|
+
def parse(landata)
|
95
|
+
landata.lines.each do |line|
|
96
|
+
# clean up the data from spaces
|
97
|
+
next if line.match(/#+/)
|
98
|
+
next if line.match(/Section/i)
|
99
|
+
line.gsub!(/\t/, '')
|
100
|
+
item = line.split(/\s+/)
|
101
|
+
key = item.first.strip.downcase
|
102
|
+
value = item.last.strip
|
103
|
+
@info[key] = value
|
104
|
+
|
105
|
+
end
|
106
|
+
return @info
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Rubyipmi::Freeipmi
|
2
|
+
class Power < Rubyipmi::Freeipmi::BaseCommand
|
3
|
+
|
4
|
+
def initialize(opts = ObservableHash.new)
|
5
|
+
super("ipmipower", opts)
|
6
|
+
end
|
7
|
+
|
8
|
+
# The command function is a wrapper that actually calls the run method
|
9
|
+
def command(opt)
|
10
|
+
@options[opt] = false
|
11
|
+
value = runcmd
|
12
|
+
@options.delete_notify(opt)
|
13
|
+
return value
|
14
|
+
end
|
15
|
+
|
16
|
+
# Turn on the system
|
17
|
+
def on
|
18
|
+
command("on")
|
19
|
+
end
|
20
|
+
|
21
|
+
# Turn off the system
|
22
|
+
def off
|
23
|
+
command("off")
|
24
|
+
end
|
25
|
+
|
26
|
+
# Power cycle the system
|
27
|
+
def cycle
|
28
|
+
# if the system is off turn it on
|
29
|
+
if off?
|
30
|
+
on
|
31
|
+
else
|
32
|
+
command("cycle")
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
# Perform a power reset on the system
|
38
|
+
def reset
|
39
|
+
command("reset")
|
40
|
+
end
|
41
|
+
|
42
|
+
# Perform a soft shutdown, like briefly pushing the power button
|
43
|
+
def softShutdown
|
44
|
+
command("soft")
|
45
|
+
end
|
46
|
+
|
47
|
+
def powerInterrupt
|
48
|
+
command("pulse")
|
49
|
+
end
|
50
|
+
|
51
|
+
# Get the power status of the system, will show either on or off
|
52
|
+
def status
|
53
|
+
value = command("stat")
|
54
|
+
if value
|
55
|
+
@result.split(":").last.chomp.strip
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Test to see if the power is on
|
60
|
+
def on?
|
61
|
+
status == "on"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Test to see if the power is off
|
65
|
+
def off?
|
66
|
+
status == "off"
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rubyipmi/freeipmi/errorcodes'
|
2
|
+
require 'rubyipmi/observablehash'
|
3
|
+
require 'rubyipmi/commands/basecommand'
|
4
|
+
require 'rubyipmi/freeipmi/commands/basecommand'
|
5
|
+
|
6
|
+
Dir[File.dirname(__FILE__) + '/commands/*.rb'].each do |file|
|
7
|
+
require "#{file.split(".rb").first}"
|
8
|
+
end
|
9
|
+
module Rubyipmi
|
10
|
+
module Freeipmi
|
11
|
+
|
12
|
+
class Connection
|
13
|
+
|
14
|
+
attr_accessor :options
|
15
|
+
|
16
|
+
|
17
|
+
def initialize(user, pass, host)
|
18
|
+
@options = Rubyipmi::ObservableHash.new
|
19
|
+
raise("Must provide a host to connect to") unless host
|
20
|
+
@options["hostname"] = host
|
21
|
+
# Credentials can also be stored in the freeipmi configuration file
|
22
|
+
# So they are not required
|
23
|
+
@options["username"] = user if user
|
24
|
+
@options["password"] = pass if pass
|
25
|
+
|
26
|
+
#getWorkArounds
|
27
|
+
end
|
28
|
+
|
29
|
+
def provider
|
30
|
+
return "freeipmi"
|
31
|
+
end
|
32
|
+
|
33
|
+
def bmc
|
34
|
+
@bmc ||= Rubyipmi::Freeipmi::Bmc.new(@options)
|
35
|
+
end
|
36
|
+
|
37
|
+
def chassis
|
38
|
+
@chassis ||= Rubyipmi::Freeipmi::Chassis.new(@options)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Rubyipmi::Ipmitool
|
2
|
+
|
3
|
+
class BaseCommand < Rubyipmi::BaseCommand
|
4
|
+
|
5
|
+
def makecommand
|
6
|
+
args = ""
|
7
|
+
# need to format the options to ipmitool format
|
8
|
+
@options.each do |k,v|
|
9
|
+
next if k == "cmdargs"
|
10
|
+
args << "-#{k} #{v} "
|
11
|
+
end
|
12
|
+
# since ipmitool requires commands to be in specific order
|
13
|
+
args << " " + options["cmdargs"]
|
14
|
+
|
15
|
+
return "#{cmd} #{args}"
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
# The findfix method acts like a recursive method and applies fixes defined in the errorcodes
|
20
|
+
# If a fix is found it is applied to the options hash, and then the last run command is retried
|
21
|
+
# until all the fixes are exhausted or a error not defined in the errorcodes is found
|
22
|
+
def findfix(result, args, debug, runmethod)
|
23
|
+
if result
|
24
|
+
# The errorcode code hash contains the fix
|
25
|
+
fix = Rubyipmi::Ipmitool::ErrorCodes.code[result]
|
26
|
+
|
27
|
+
if not fix
|
28
|
+
raise "Ipmi Fix not found, email author with error: #{result}"
|
29
|
+
else
|
30
|
+
@options.merge_notify!(fix)
|
31
|
+
# retry the last called method
|
32
|
+
# its quicker to explicitly call these commands than calling a command block
|
33
|
+
if runmethod == "runcmd"
|
34
|
+
runcmd(debug)
|
35
|
+
else
|
36
|
+
runcmd_without_opts(args, debug)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
def throwError
|
44
|
+
# Find out what kind of error is happening, parse results
|
45
|
+
# Check for authentication or connection issue
|
46
|
+
#puts "ipmi call: #{@lastcall}"
|
47
|
+
|
48
|
+
if @result =~ /timeout|timed\ out/
|
49
|
+
code = "ipmi call: #{@lastcall} timed out"
|
50
|
+
raise code
|
51
|
+
else
|
52
|
+
# ipmitool spits out many errors so for now we will just take the first error
|
53
|
+
code = @result.split(/\r\n/).first if not @result.empty?
|
54
|
+
end
|
55
|
+
throw :ipmierror, code
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Rubyipmi::Ipmitool
|
2
|
+
|
3
|
+
class Bmc < Rubyipmi::Ipmitool::BaseCommand
|
4
|
+
|
5
|
+
attr_accessor :config
|
6
|
+
|
7
|
+
def initialize(opts = ObservableHash.new)
|
8
|
+
super("ipmitool", opts)
|
9
|
+
@bmcinfo = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def lan
|
13
|
+
@lan ||= Rubyipmi::Ipmitool::Lan.new(@options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def info
|
17
|
+
if @bmcinfo.length > 0
|
18
|
+
@bmcinfo
|
19
|
+
else
|
20
|
+
retrieve
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def guid
|
25
|
+
@options["cmdargs"] = "bmc guid"
|
26
|
+
value = runcmd()
|
27
|
+
@options.delete_notify("cmdargs")
|
28
|
+
if value
|
29
|
+
@result.lines.each { | line |
|
30
|
+
line.chomp
|
31
|
+
if line =~ /GUID/
|
32
|
+
line.split(":").last.strip
|
33
|
+
end
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
# Some sample data for info
|
40
|
+
# Device ID : 17
|
41
|
+
# Device Revision : 1
|
42
|
+
# Firmware Revision : 2.9
|
43
|
+
# IPMI Version : 2.0
|
44
|
+
# Manufacturer ID : 11
|
45
|
+
# Manufacturer Name : Hewlett-Packard
|
46
|
+
# Product ID : 8192 (0x2000)
|
47
|
+
# Product Name : Unknown (0x2000)
|
48
|
+
# Device Available : yes
|
49
|
+
# Provides Device SDRs : yes
|
50
|
+
# Additional Device Support :
|
51
|
+
# Sensor Device
|
52
|
+
# SDR Repository Device
|
53
|
+
# SEL Device
|
54
|
+
# FRU Inventory Device
|
55
|
+
# Aux Firmware Rev Info :
|
56
|
+
# 0x00
|
57
|
+
# 0x00
|
58
|
+
# 0x00
|
59
|
+
# 0x30
|
60
|
+
|
61
|
+
|
62
|
+
# This function will get the bmcinfo and return a hash of each item in the info
|
63
|
+
def retrieve
|
64
|
+
@options["cmdargs"] = "bmc info"
|
65
|
+
status = runcmd
|
66
|
+
@options.delete_notify("cmdargs")
|
67
|
+
subkey = nil
|
68
|
+
if not status
|
69
|
+
raise @result
|
70
|
+
else
|
71
|
+
@result.lines.each do |line|
|
72
|
+
# clean up the data from spaces
|
73
|
+
item = line.split(':')
|
74
|
+
key = item.first.strip
|
75
|
+
value = item.last.strip
|
76
|
+
# if the following condition is met we have subvalues
|
77
|
+
if key == value and not subkey
|
78
|
+
subkey = key
|
79
|
+
@bmcinfo[subkey] = []
|
80
|
+
elsif key == value and subkey
|
81
|
+
# subvalue found
|
82
|
+
@bmcinfo[subkey] << value
|
83
|
+
else
|
84
|
+
# Normal key/value pair with no subkeys
|
85
|
+
subkey = nil
|
86
|
+
@bmcinfo[key] = value
|
87
|
+
end
|
88
|
+
end
|
89
|
+
return @bmcinfo
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|