Module: Rubyipmi

Defined in:
lib/rubyipmi.rb,
lib/rubyipmi/version.rb,
lib/rubyipmi/observablehash.rb,
lib/rubyipmi/freeipmi/connection.rb,
lib/rubyipmi/ipmitool/connection.rb,
lib/rubyipmi/ipmitool/errorcodes.rb,
lib/rubyipmi/commands/basecommand.rb,
lib/rubyipmi/commands/mixins/power_mixin.rb,
lib/rubyipmi/commands/mixins/sensors_mixin.rb

Defined Under Namespace

Modules: Freeipmi, Ipmitool, PowerMixin, SensorsMixin Classes: BaseCommand, ObservableHash

Constant Summary collapse

PRIV_TYPES =
['CALLBACK', 'USER', 'OPERATOR', 'ADMINISTRATOR']
VERSION =
'0.12.0'.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Attribute Details

#log_levelObject

Returns the value of attribute log_level.



34
35
36
# File 'lib/rubyipmi.rb', line 34

def log_level
  @log_level
end

#loggerObject

Returns the value of attribute logger.



34
35
36
# File 'lib/rubyipmi.rb', line 34

def logger
  @logger
end

Class Method Details

.capture3(cmd) ⇒ Object

test-friendly capture3



149
150
151
# File 'lib/rubyipmi.rb', line 149

def self.capture3(cmd)
  return Open3.capture3(cmd)
end

.connect(user, pass, host, provider = 'any', opts = {:driver => 'lan20', :timeout => 'default'}) ⇒ Object

The connect method will create a connection object based the provider type passed in If provider is left blank the function will use the first available provider When the driver is set to auto, rubyipmi will try and figure out which driver to use by common error messages. We will most likely be using the lan20 driver, but in order to support a wide use case we default to auto.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/rubyipmi.rb', line 76

def self.connect(user, pass, host, provider = 'any', opts = {:driver => 'lan20', :timeout => 'default'})
  # use this variable to reduce cmd calls
  installed = false

  # if the user supplied nil, we want to fix this automatically
  opts = {:driver => 'lan20', :timeout => 'default'} if opts.nil?

  # convert all keys to symbols for opts, we can't assume the user will use symbols
  opts.keys.each do |key|
    opts[(key.to_sym rescue key) || key] = opts.delete(key)
  end

  # allow the user to specify an options hash instead of the provider
  # in the future I would stop using the provider and use the opts hash instead to get the provider
  # This allows us to be a little more flexible if the user is doesn't supply us what we need.
  if provider.kind_of?(Hash)
    opts = provider
    provider = opts[:provider] ||= 'any'
  end

  # Verify options just in case user passed in a incomplete hash
  opts[:driver] ||= 'lan20'
  opts[:timeout] ||= 'default'

  if opts[:privilege] && !supported_privilege_type?(opts[:privilege])
    logger.error("Invalid privilege type :#{opts[:privilege]}, must be one of: #{PRIV_TYPES.join("\n")}") if logger
    raise "Invalid privilege type :#{opts[:privilege]}, must be one of: #{PRIV_TYPES.join("\n")}"
  end

  # use the first available provider
  if provider == 'any'
    if is_provider_installed?("freeipmi")
      provider = "freeipmi"
      installed = true
    elsif is_provider_installed?("ipmitool")
      provider = "ipmitool"
      installed = true
    else
      logger.error("No IPMI provider is installed, please install freeipmi or ipmitool")
      raise "No IPMI provider is installed, please install freeipmi or ipmitool"
    end
  end

  # Support multiple drivers
  # Note: these are just generic names of drivers that need to be specified for each provider
  unless valid_drivers.include?(opts[:driver])
    logger.debug("You must specify a valid driver: #{valid_drivers.join(',')}") if logger
    raise "You must specify a valid driver: #{valid_drivers.join(',')}"
  end

  # If the provider is available create a connection object
  if installed || is_provider_installed?(provider)
    if provider == "freeipmi"
      Rubyipmi::Freeipmi::Connection.new(user, pass, host, opts)
    elsif provider == "ipmitool"
      Rubyipmi::Ipmitool::Connection.new(user, pass, host, opts)
    else
      logger.error("Incorrect provider given, must use one of #{valid_providers.join(', ')}") if logger
      raise "Incorrect provider given, must use one of #{valid_providers.join(', ')}"
    end
  else
    # Can't find the provider command line tool, maybe try other provider?
    logger.error("The IPMI provider: #{provider} is not installed") if logger
    raise "The IPMI provider: #{provider} is not installed"
  end
end

.get_diag(user, pass, host, opts = {:driver => 'lan20', :timeout => 'default'}) ⇒ Object

gets data from the bmc device and puts in a hash for diagnostics



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/rubyipmi.rb', line 195

def self.get_diag(user, pass, host, opts = {:driver => 'lan20', :timeout => 'default'})
  data = {}
  if Rubyipmi.is_provider_installed?('freeipmi')
    freeconn = Rubyipmi.connect(user, pass, host, 'freeipmi', opts)
    if freeconn
      puts "Retrieving freeipmi data"
      data[:freeipmi] = freeconn.get_diag
    end
  end
  if Rubyipmi.is_provider_installed?('ipmitool')
    ipmiconn = Rubyipmi.connect(user, pass, host, 'ipmitool', opts)
    if ipmiconn
      puts "Retrieving ipmitool data"
      data[:ipmitool] = ipmiconn.get_diag
    end
  end
  File.open('/tmp/rubyipmi_diag_data.txt', 'w') { |f| f.write(data) }
  puts "Created file /tmp/rubyipmi_diag_data.txt"
end

.is_provider_installed?(provider) ⇒ Boolean

Return true or false if the provider is available



163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/rubyipmi.rb', line 163

def self.is_provider_installed?(provider)
  case provider
  when "freeipmi"
    cmdpath = locate_command('ipmipower')
  when "ipmitool"
    cmdpath = locate_command('ipmitool')
  else
    logger.error("Invalid BMC provider type #{provider}") if logger
    false
  end
  # return false if command was not found
  !cmdpath.nil?
end

.locate_command(commandname) ⇒ Object

method used to find the command which also makes it easier to mock with



154
155
156
157
158
159
160
# File 'lib/rubyipmi.rb', line 154

def self.locate_command(commandname)
  stdout, stderr, status = Open3.capture3("which #{commandname}")
  logger&.error("Which command returned: #{stderr}") unless status.success?

  return nil unless status.success?
  stdout
end

.log_level=(level) ⇒ Object

sets the log level, this should be called first if logging to a file is desired if you wish to customize the logging options, set the logger yourself with logger= valid levels are of the type Logger::INFO, Logger::DEBUG, Logger::ERROR, …



45
46
47
# File 'lib/rubyipmi.rb', line 45

def self.log_level=(level)
  @log_level = level
end

.loggerObject

this is an read only method that only creates a real logger if the log_level is set if the log_level is not setup it creates a null logger which logs nothing



51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rubyipmi.rb', line 51

def self.logger
  # by default the log will be set to info
  unless @logger
    if @log_level && @log_level >= 0
      @logger = Logger.new('/tmp/rubyipmi.log')
      @logger.progname = 'Rubyipmi'
      @logger.level = @log_level
    else
      @logger = NullLogger.new
    end
  end
  @logger
end

.logger=(log) ⇒ Object

set a logger instance yourself to customize where the logs should go you will need to set the log level yourself



38
39
40
# File 'lib/rubyipmi.rb', line 38

def self.logger=(log)
  @logger = log
end

.provider_installed?Boolean

returns true if any of the providers are installed



182
183
184
# File 'lib/rubyipmi.rb', line 182

def self.provider_installed?
  providers_installed.length > 0
end

.providersObject



177
178
179
# File 'lib/rubyipmi.rb', line 177

def self.providers
  ["freeipmi", "ipmitool"]
end

.providers_installedObject



186
187
188
189
190
191
192
# File 'lib/rubyipmi.rb', line 186

def self.providers_installed
  available = []
  providers.each do |prov|
    available << prov if is_provider_installed?(prov)
  end
  available
end

.supported_privilege_type?(type) ⇒ Boolean

returns boolean true if privilege type is valid



144
145
146
# File 'lib/rubyipmi.rb', line 144

def self.supported_privilege_type?(type)
  PRIV_TYPES.include?(type)
end

.valid_driversObject



65
66
67
# File 'lib/rubyipmi.rb', line 65

def self.valid_drivers
  ['auto', "lan15", "lan20", "open"]
end

.valid_providersObject



69
70
71
# File 'lib/rubyipmi.rb', line 69

def self.valid_providers
  ['auto', 'ipmitool', 'freeipmi']
end