ruby-ipmitool 0.1

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