Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ doc
Gemfile.lock
# bundler
.bundle
vendor/bundle
Gemfile.lock
# built gems
*.gem
Expand Down
28 changes: 15 additions & 13 deletions lib/rubyipmi.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

# Copyright (C) 2014 Corey Osman
#
# This library is free software; you can redistribute it and/or
Expand All @@ -22,15 +24,13 @@
require 'open3'

class NullLogger < Logger
def initialize(*_args)
end
def initialize(*_args); end

def add(*_args, &_block)
end
def add(*_args, &_block); end
end

module Rubyipmi
PRIV_TYPES = ['CALLBACK', 'USER', 'OPERATOR', 'ADMINISTRATOR']
PRIV_TYPES = ['CALLBACK', 'USER', 'OPERATOR', 'ADMINISTRATOR'].freeze
attr_accessor :logger, :log_level

# set a logger instance yourself to customize where the logs should go
Expand Down Expand Up @@ -69,6 +69,7 @@ def self.valid_drivers
def self.valid_providers
['auto', 'ipmitool', 'freeipmi']
end

# 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
Expand Down Expand Up @@ -98,7 +99,7 @@ def self.connect(user, pass, host, provider = 'any', 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
logger&.error("Invalid privilege type :#{opts[:privilege]}, must be one of: #{PRIV_TYPES.join("\n")}")
raise "Invalid privilege type :#{opts[:privilege]}, must be one of: #{PRIV_TYPES.join("\n")}"
end

Expand All @@ -119,7 +120,7 @@ def self.connect(user, pass, host, provider = 'any', opts = {:driver => 'lan20',
# 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
logger&.debug("You must specify a valid driver: #{valid_drivers.join(',')}")
raise "You must specify a valid driver: #{valid_drivers.join(',')}"
end

Expand All @@ -130,12 +131,12 @@ def self.connect(user, pass, host, provider = 'any', opts = {:driver => 'lan20',
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
logger&.error("Incorrect provider given, must use one of #{valid_providers.join(', ')}")
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
logger&.error("The IPMI provider: #{provider} is not installed")
raise "The IPMI provider: #{provider} is not installed"
end
end
Expand All @@ -147,7 +148,7 @@ def self.supported_privilege_type?(type)

# test-friendly capture3
def self.capture3(cmd)
return Open3.capture3(*cmd)
Open3.capture3(*cmd)
end

# method used to find the command which also makes it easier to mock with
Expand All @@ -156,6 +157,7 @@ def self.locate_command(commandname)
logger&.error("Which command returned: #{stderr}") unless status.success?

return nil unless status.success?

stdout.strip
end

Expand All @@ -167,7 +169,7 @@ def self.is_provider_installed?(provider)
when "ipmitool"
cmdpath = locate_command('ipmitool')
else
logger.error("Invalid BMC provider type #{provider}") if logger
logger&.error("Invalid BMC provider type #{provider}")
false
end
# return false if command was not found
Expand All @@ -180,7 +182,7 @@ def self.providers

# returns true if any of the providers are installed
def self.provider_installed?
providers_installed.length > 0
providers_installed.length.positive?
end

def self.providers_installed
Expand Down Expand Up @@ -208,7 +210,7 @@ def self.get_diag(user, pass, host, opts = {:driver => 'lan20', :timeout => 'def
data[:ipmitool] = ipmiconn.get_diag
end
end
File.open('/tmp/rubyipmi_diag_data.txt', 'w') { |f| f.write(data) }
File.write('/tmp/rubyipmi_diag_data.txt', data)
puts "Created file /tmp/rubyipmi_diag_data.txt"
end
end
25 changes: 13 additions & 12 deletions lib/rubyipmi/commands/basecommand.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# frozen_string_literal: true

require "observer"
require 'tempfile'
require 'rubyipmi'

module Rubyipmi
class BaseCommand
include Observable
attr_reader :cmd, :max_retry_count

attr_reader :cmd, :max_retry_count, :lastcall, :result
attr_accessor :options, :passfile
attr_reader :lastcall, :result

def logger
Rubyipmi.logger
Expand Down Expand Up @@ -37,7 +39,7 @@ def initialize(commandname, opts = ObservableHash.new)
end

def locate_command(commandname)
unless location = Rubyipmi.locate_command(commandname)
unless (location = Rubyipmi.locate_command(commandname))
logger&.error("#{commandname} command not found, is #{commandname} installed?")
raise "#{commandname} command not found, is #{commandname} installed?"
end
Expand All @@ -49,8 +51,8 @@ def locate_command(commandname)
def runcmd
@success = false
@success = run
logger.debug(@lastcall.inspect) unless @lastcall.nil? if logger
logger.debug(@result) unless @result.nil? if logger
logger&.debug(@lastcall.inspect) unless @lastcall.nil?
logger&.debug(@result) unless @result.nil?
@success
end

Expand All @@ -59,29 +61,27 @@ def run
# we also don't want to add this to the initialize since mocking is difficult and we don't want to
# throw errors upon object creation
retrycount = 0
process_status = false
@cmd = locate_command(@cmdname)
setpass
@result = nil
logger.debug(makecommand) if logger
logger&.debug(makecommand)
begin
command = makecommand
@lastcall = command
@result, @result_err, status = Rubyipmi.capture3(command)
# sometimes the command tool does not return the correct result, validate it with additional code
process_status = validate_status(status)
rescue
validate_status(status)
rescue StandardError
if retrycount < max_retry_count
find_fix(@result)
retrycount = retrycount.next
retry
else
logger.error("Exhausted all auto fixes, cannot determine what the problem is") if logger
logger&.error("Exhausted all auto fixes, cannot determine what the problem is")
raise "Exhausted all auto fixes, cannot determine what the problem is"
end
ensure
removepass
process_status
end
end

Expand All @@ -91,11 +91,12 @@ def run
# this must be overrided in the subclass, as there are no generic errors that fit both providers
def find_fix(result)
return unless result

# The errorcode code hash contains the fix
begin
fix = ErrorCodes.search(result)
@options.merge_notify!(fix)
rescue
rescue StandardError
Rubyipmi.logger.debug("Could not find fix for error code: \n#{result}") if logger
raise "Could not find fix for error code: \n#{result}"
end
Expand Down
2 changes: 2 additions & 0 deletions lib/rubyipmi/commands/mixins/power_mixin.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

module Rubyipmi
module PowerMixin
# Turn the system on
Expand Down
16 changes: 8 additions & 8 deletions lib/rubyipmi/commands/mixins/sensors_mixin.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# frozen_string_literal: true

module Rubyipmi
module SensorsMixin
def refresh
@sensors = nil
@list = nil
list
end

def list
@sensors ||= parse(getsensors)
@list ||= parse(getsensors)
end

def count
Expand All @@ -27,18 +29,16 @@ def fanlist(refreshdata = false)
def templist(refreshdata = false)
refresh if refreshdata
list.each_with_object({}) do |(name, sensor), tlist|
tlist[name] = sensor if (sensor[:unit] =~ /.*degree.*/ || name =~ /.*temp.*/)
tlist[name] = sensor if sensor[:unit] =~ /.*degree.*/ || name =~ /.*temp.*/
end
end

private

def method_missing(method, *_args, &_block)
if !list.key?(method.to_s)
raise NoMethodError
else
list[method.to_s]
end
raise NoMethodError unless list.key?(method.to_s)

list[method.to_s]
end

def parse(data)
Expand Down
21 changes: 12 additions & 9 deletions lib/rubyipmi/freeipmi/commands/basecommand.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

require 'rubyipmi/freeipmi/errorcodes'

module Rubyipmi::Freeipmi
Expand All @@ -20,10 +22,11 @@ def makecommand
# must remove from command line as its handled via conf file
next if k == 'password'
next if k == 'username'
if !v
"--#{k}"
else

if v
"--#{k}=#{v}"
else
"--#{k}"
end
end

Expand All @@ -39,11 +42,10 @@ def validate_status(exitstatus)
# essentially any result greater than 23 characters is an error
raise "Error occurred" if @result.length > 23
when "bmc-config"
if @result.length > 100 && exitstatus.success?
return true
else
raise "Error occurred"
end
return true if @result.length > 100 && exitstatus.success?

raise "Error occurred"

else
super
end
Expand All @@ -54,11 +56,12 @@ def validate_status(exitstatus)
# until all the fixes are exhausted or a error not defined in the errorcodes is found
def find_fix(result)
return unless result

# The errorcode code hash contains the fix
begin
fix = ErrorCodes.search(result)
@options.merge_notify!(fix)
rescue
rescue StandardError
raise "Could not find fix for error code: \n#{result}"
end
end
Expand Down
8 changes: 5 additions & 3 deletions lib/rubyipmi/freeipmi/commands/bmc.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

module Rubyipmi::Freeipmi
class Bmc < Rubyipmi::Freeipmi::BaseCommand
# attr_accessor :options
Expand All @@ -16,7 +18,7 @@ def version
end

def info
if @bmcinfo.length > 0
if @bmcinfo.length.positive?
@bmcinfo
else
information.retrieve
Expand All @@ -40,11 +42,11 @@ def lan
end

def information
@info ||= Rubyipmi::Freeipmi::BmcInfo.new(options)
@information ||= Rubyipmi::Freeipmi::BmcInfo.new(options)
end

def device
@bmcdevice ||= Rubyipmi::Freeipmi::BmcDevice.new(options)
@device ||= Rubyipmi::Freeipmi::BmcDevice.new(options)
end
end
end
6 changes: 4 additions & 2 deletions lib/rubyipmi/freeipmi/commands/bmcconfig.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

module Rubyipmi::Freeipmi
class BmcConfig < Rubyipmi::Freeipmi::BaseCommand
def initialize(opts = ObservableHash.new)
Expand Down Expand Up @@ -45,11 +47,11 @@ def configuration

# Returns a list of available sections to inspect
def listsections
if @sections.length < 1
if @sections.empty?
@options["listsections"] = false
value = runcmd
@options.delete_notify("listsections")
@sections = @result.split(/\n/) if value
@sections = @result.split("\n") if value
end
@sections
end
Expand Down
4 changes: 3 additions & 1 deletion lib/rubyipmi/freeipmi/commands/bmcdevice.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

module Rubyipmi::Freeipmi
class BmcDevice < Rubyipmi::Freeipmi::BaseCommand
def initialize(opts = ObservableHash.new)
Expand All @@ -18,7 +20,7 @@ def reset(type = 'cold')
key = "#{type}-reset"
command(key)
else
logger.error("reset type: #{type} is not a valid choice, use warm or cold") if logger
logger&.error("reset type: #{type} is not a valid choice, use warm or cold")
raise "reset type: #{type} is not a valid choice, use warm or cold"
end
end
Expand Down
Loading