ruby-ipmitool 0.1

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 (2) hide show
  1. data/lib/ruby-ipmitool.rb +190 -0
  2. metadata +66 -0
@@ -0,0 +1,190 @@
1
+ require 'ping'
2
+
3
+ module Kernel
4
+ private
5
+ def this_method_name
6
+ caller[0] =~ /`([^']*)'/ && $1
7
+ end
8
+ end
9
+
10
+ class Hash
11
+ def method_missing(name, *args, &blk)
12
+ if self.keys.map(&:to_sym).include? name.to_sym
13
+ return self[name.to_sym]
14
+ else
15
+ super
16
+ end
17
+ end
18
+ end
19
+
20
+
21
+ =begin rdoc
22
+ This utility wraps the UNIX ipmitool command to provide common functions
23
+
24
+ All methods in this class return a hash, which can be read as accessors.
25
+
26
+ For more information on the output and its meanings, see the official ipmitool man page at http://ipmitool.sourceforge.net/manpage.html
27
+ =end
28
+
29
+ class Ipmitool
30
+ attr_reader :conn
31
+
32
+ #Instantiates a new Ipmitool object. Takes a hash containing :host, :user, and :password.
33
+ #
34
+ #Ex: Ipmitool.new(:host => '192.168.1.1', :user => 'username', :password => 'password')
35
+ def initialize(conn = {})
36
+ conn[:check_host] ||= true
37
+ raise ArgumentError, "Wrong number of arguments" if conn.count != 4
38
+ raise ArgumentError, "Host is required" if conn[:host].nil?
39
+ raise ArgumentError, "User is required" if conn[:user].nil?
40
+ raise ArgumentError, "Password is required" if conn[:password].nil?
41
+ @conn = conn
42
+ @conn[:binary] = `which ipmitool`.chomp
43
+ binary = system('which ipmitool > /dev/null')
44
+ raise ArgumentError, "Missing ipmitool" unless binary
45
+ if conn[:check_host]
46
+ raise ArgumentError, "Host is down or invalid!" unless check_host
47
+ end
48
+ end
49
+
50
+ #Run a ping check to see if the host is responding
51
+ def check_host
52
+ return Ping.pingecho(@conn[:host], 2)
53
+ end
54
+
55
+ #Read sensor data from ipmitool and return a hash containing the value
56
+ #
57
+ #Returned format is {:sensor_name => ['value1', 'value2']}
58
+ #Ex. Ipmitool.new(:host => '192.168.1.1', :user => 'username', :password => 'password').sensor.fan1
59
+ def sensor
60
+ sensor_output = run_command(this_method_name).split("\n")
61
+ sensor_hash = split_output(sensor_output, '|')
62
+ return sensor_hash = sensor_hash.each { |k,v| sensor_hash[k.to_sym] = v.split(/\s\|\s/) }
63
+ end
64
+
65
+ #Same as sensor, but the output is a bit more formatted for everyday use
66
+ def sdr
67
+ sdr_output = run_command(this_method_name).split("\n")
68
+ sdr_hash = split_output(sdr_output, '|')
69
+ return sdr_hash = sdr_hash.each { |k,v| sdr_hash[k.to_sym] = v.split(/\s\|\s/) }
70
+ end
71
+
72
+ #Query and issue commands to the chassis itself. Useful for powering a box on and off, resets, etc
73
+ #
74
+ #Ex ipmi.chassis("power", "on").chassis_power_control
75
+ def chassis(chassis_command, *command_args)
76
+ chassis_hash = Hash.new
77
+ case chassis_command
78
+ when "status", "restart_cause", "poh", "selftest"
79
+ chassis_output = run_command(this_method_name, chassis_command)
80
+ chassis_output = chassis_output.split("\n")
81
+ chassis_hash = split_output(chassis_output, ':')
82
+ when "power"
83
+ raise ArgumentError, "#{chassis_command} requires an additional argument" if command_args.empty?
84
+ chassis_output = run_command(this_method_name, "#{chassis_command} #{command_args}")
85
+ chassis_hash = split_output(chassis_output.to_a, ":")
86
+ return chassis_hash
87
+ when "policy"
88
+ raise ArgumentError, "Policy requires a state" if command_args.empty?
89
+ if command_args.to_s == 'list'
90
+ chassis_output = run_command(this_method_name, "#{chassis_command} #{command_args}")
91
+ chassis_hash = split_output(chassis_output.split("\n"), ":")
92
+ else
93
+ chassis_hash[:result] = run_command(this_method_name, "#{chassis_command} #{command_args}").gsub("\n","")
94
+ return chassis_hash
95
+ end
96
+ when "bootdev"
97
+ raise ArgumentError, "bootdev requires an additional argument" if command_args.empty?
98
+ chassis_hash[:result] = run_command(this_method_name, "#{chassis_command} #{command_args}").gsub("\n","")
99
+ return chassis_hash
100
+ else
101
+ raise ArgumentError, "Invalid Chassis Command"
102
+ end
103
+ end
104
+
105
+ #Shortcut to ipmi.chassis("power"). Values returned are formatted exactly as ipmi.chassis.
106
+ #
107
+ #Ex. ipmi.power("on")
108
+ def power(power_command)
109
+ return chassis("power", power_command)
110
+ end
111
+
112
+ #Set channel options, including authentication. For options that require more than 1 option, that should be specified as separate options to the method.
113
+ #
114
+ #Ex. ipmi.channel("getciphers", "ipmi", "1").inspect
115
+ #
116
+ #The setaccess function gives no output
117
+ def channel(channel_command, *command_args)
118
+ channel_hash = Hash.new
119
+ case channel_command
120
+ when "authcap"
121
+ raise ArgumentError, "Authcap requires a channel number and privilege" if command_args.empty?
122
+ channel_output = run_command(this_method_name, "#{channel_command} #{command_args.join(' ')}")
123
+ return channel_hash = split_output(channel_output, ':')
124
+ when "getaccess"
125
+ raise ArgumentError, "Authcap requires a channel number and uid" if command_args.empty?
126
+ user_hash = user("list", command_args[0])
127
+ raise ArgumentError, "Invalid user specified" unless user_hash.has_key?("uid#{command_args[1]}".to_sym)
128
+ channel_output = run_command(this_method_name, "#{channel_command} #{command_args.join(' ')}")
129
+ channel_hash = split_output(channel_output, ':')
130
+ when "setaccess"
131
+ raise ArgumentError, "Authcap requires a channel number, uid, and privilege level" if command_args.empty?
132
+ user_hash = user("list", command_args[0])
133
+ raise ArgumentError, "Invalid user specified" unless user_hash.has_key?("uid#{command_args[1]}".to_sym)
134
+ command_args[2] = "privilege=#{command_args[2]}"
135
+ run_command(this_method_name, "#{channel_command} #{command_args.join(' ')}")
136
+ when "info"
137
+ raise ArgumentError, "Info requires a channel number" if command_args.empty?
138
+ channel_output = run_command(this_method_name, "#{channel_command} #{command_args}")
139
+ channel_output = channel_output.grep(/:/).each { |line| line.strip! }.delete_if { |line| line =~ /:$/ }
140
+ return channel_hash = split_output(channel_output, ':')
141
+ when "getciphers"
142
+ raise ArgumentError, "Info requires a protocol and channel number" if command_args.empty?
143
+ channel_output = run_command(this_method_name, "#{channel_command} #{command_args.join(' ')}").grep(/^[0-9]/)
144
+ channel_output.each { |c| channel_hash["id#{c.split[0]}".to_sym] = c.split[1..-1] }
145
+ return channel_hash
146
+ else
147
+ raise ArgumentError, "Invalid Channel Command"
148
+ end
149
+ end
150
+
151
+ #Add and modify users.
152
+ #
153
+ #set name, set password, disable, enable, and priv do not give output
154
+ def user(user_command, *command_args)
155
+ user_hash = Hash.new
156
+ case user_command
157
+ when "list"
158
+ raise ArgumentError, "List requires a channel number" if command_args.empty?
159
+ user_output = run_command(this_method_name, "#{user_command} #{command_args}").grep(/^[0-9]/)
160
+ user_output.each { |u| user_hash["uid#{u.split[0]}".to_sym] = u.split[1..-1] }
161
+ return user_hash
162
+ when "set name", "set password", "priv"
163
+ raise ArgumentError, "#{user_command} requires 2 arguments" if command_args.empty?
164
+ run_command(this_method_name, "#{user_command} #{command_args.join(' ')}")
165
+ when "disable", "enable"
166
+ raise ArgumentError, "#{user_command} requires a UID" if command_args.empty?
167
+ run_command(this_method_name, "#{user_command} #{command_args}")
168
+ else
169
+ raise ArgumentError, "Invalid User Command"
170
+ end
171
+ end
172
+
173
+ #This function takes no arguments and returns logging output
174
+ def sel
175
+ sel_output = run_command(this_method_name).split("\n").grep(/:/)
176
+ return sel_hash = split_output(sel_output, ':')
177
+ end
178
+
179
+ private
180
+ def run_command(command, *args)
181
+ `#{@conn[:binary]} -H #{@conn[:host]} -U #{@conn[:user]} -P #{@conn[:password]} #{command} #{args unless args.nil?}`.downcase!
182
+ end
183
+
184
+ def split_output(array, delimiter)
185
+ split_hash = Hash.new
186
+ delimiter = "\\#{delimiter}"
187
+ array.each { |stat| split_hash[stat.split(/\s*#{delimiter}\s?/)[0].gsub(/\s+/," ").gsub(' ','_').gsub('.','').gsub(/^#/,"number").to_sym] = stat.split(/\s*#{delimiter}\s?/,2)[1].strip }
188
+ return split_hash
189
+ end
190
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-ipmitool
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ version: "0.1"
10
+ platform: ruby
11
+ authors:
12
+ - Eugene Howe
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-04-23 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Wraps most fucntionality of ipmitool including user, sensor, channel, and chassis functions
22
+ email:
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/ruby-ipmitool.rb
31
+ has_rdoc: true
32
+ homepage:
33
+ licenses: []
34
+
35
+ post_install_message:
36
+ rdoc_options: []
37
+
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ hash: 3
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ requirements: []
59
+
60
+ rubyforge_project:
61
+ rubygems_version: 1.5.0
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Wrapper for the linux ipmitool command
65
+ test_files: []
66
+