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.
Files changed (40) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +14 -0
  4. data/Gemfile.lock +33 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +267 -0
  7. data/README.rdoc +18 -0
  8. data/Rakefile +49 -0
  9. data/VERSION +1 -0
  10. data/lib/rubyipmi.rb +80 -0
  11. data/lib/rubyipmi/commands/basecommand.rb +171 -0
  12. data/lib/rubyipmi/freeipmi/commands/basecommand.rb +60 -0
  13. data/lib/rubyipmi/freeipmi/commands/bmc.rb +37 -0
  14. data/lib/rubyipmi/freeipmi/commands/bmcconfig.rb +57 -0
  15. data/lib/rubyipmi/freeipmi/commands/bmcinfo.rb +76 -0
  16. data/lib/rubyipmi/freeipmi/commands/chassis.rb +123 -0
  17. data/lib/rubyipmi/freeipmi/commands/chassisconfig.rb +100 -0
  18. data/lib/rubyipmi/freeipmi/commands/lan.rb +111 -0
  19. data/lib/rubyipmi/freeipmi/commands/power.rb +72 -0
  20. data/lib/rubyipmi/freeipmi/connection.rb +43 -0
  21. data/lib/rubyipmi/freeipmi/errorcodes.rb +15 -0
  22. data/lib/rubyipmi/ipmitool/commands/basecommand.rb +60 -0
  23. data/lib/rubyipmi/ipmitool/commands/bmc.rb +95 -0
  24. data/lib/rubyipmi/ipmitool/commands/chassis.rb +106 -0
  25. data/lib/rubyipmi/ipmitool/commands/chassisconfig.rb +52 -0
  26. data/lib/rubyipmi/ipmitool/commands/lan.rb +162 -0
  27. data/lib/rubyipmi/ipmitool/commands/power.rb +74 -0
  28. data/lib/rubyipmi/ipmitool/connection.rb +46 -0
  29. data/lib/rubyipmi/ipmitool/errorcodes.rb +18 -0
  30. data/lib/rubyipmi/observablehash.rb +20 -0
  31. data/rubyipmi.gemspec +91 -0
  32. data/spec/bmc_spec.rb +35 -0
  33. data/spec/chassis_config_spec.rb +38 -0
  34. data/spec/chassis_spec.rb +24 -0
  35. data/spec/connection_spec.rb +31 -0
  36. data/spec/lan_spec.rb +61 -0
  37. data/spec/power_spec.rb +40 -0
  38. data/spec/rubyipmi_spec.rb +59 -0
  39. data/spec/spec_helper.rb +12 -0
  40. 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,15 @@
1
+ module Rubyipmi::Freeipmi
2
+
3
+ class ErrorCodes
4
+
5
+ @@code = {
6
+ "authentication type unavailable for attempted privilege level" => {"driver-type" => "LAN_2_0"},
7
+
8
+ }
9
+
10
+ def self.code
11
+ @@code
12
+ end
13
+ end
14
+
15
+ 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