Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

140 lines (121 sloc) 4.005 kB
# An actual fact resolution mechanism. These are largely just chunks of
# code, with optional confinements restricting the mechanisms to only working on
# specific systems. Note that the confinements are always ANDed, so any
# confinements specified must all be true for the resolution to be
# suitable.
require 'facter/util/confine'
require 'timeout'
require 'rbconfig'
class Facter::Util::Resolution
attr_accessor :interpreter, :code, :name, :timeout
def self.have_which
if ! defined?(@have_which) or @have_which.nil?
if Config::CONFIG['host_os'] =~ /mswin/
@have_which = false
else
%x{which which >/dev/null 2>&1}
@have_which = ($? == 0)
end
end
@have_which
end
# Execute a chunk of code.
def self.exec(code, interpreter = "/bin/sh")
raise ArgumentError, "non-sh interpreters are not currently supported" unless interpreter == "/bin/sh"
binary = code.split(/\s+/).shift
if have_which
path = nil
if binary !~ /^\//
path = %x{which #{binary} 2>/dev/null}.chomp
# we don't have the binary necessary
return nil if path == "" or path.match(/Command not found\./)
else
path = binary
end
return nil unless FileTest.exists?(path)
end
out = nil
begin
out = %x{#{code}}.chomp
rescue => detail
$stderr.puts detail
return nil
end
if out == ""
return nil
else
return out
end
end
# Add a new confine to the resolution mechanism.
def confine(confines)
confines.each do |fact, values|
@confines.push Facter::Util::Confine.new(fact, *values)
end
end
# Create a new resolution mechanism.
def initialize(name)
@name = name
@confines = []
@value = nil
@timeout = 0
end
# Return the number of confines.
def length
@confines.length
end
# We need this as a getter for 'timeout', because some versions
# of ruby seem to already have a 'timeout' method and we can't
# seem to override the instance methods, somehow.
def limit
@timeout
end
# Set our code for returning a value.
def setcode(string = nil, interp = nil, &block)
if string
@code = string
@interpreter = interp || "/bin/sh"
else
unless block_given?
raise ArgumentError, "You must pass either code or a block"
end
@code = block
end
end
# Is this resolution mechanism suitable on the system in question?
def suitable?
unless defined? @suitable
@suitable = ! @confines.detect { |confine| ! confine.true? }
end
return @suitable
end
def to_s
return self.value()
end
# How we get a value for our resolution mechanism.
def value
result = nil
return result if @code == nil and @interpreter == nil
begin
Timeout.timeout(limit) do
if @code.is_a?(Proc)
result = @code.call()
else
result = Facter::Util::Resolution.exec(@code,@interpreter)
end
end
rescue Timeout::Error => detail
warn "Timed out seeking value for %s" % self.name
# This call avoids zombies -- basically, create a thread that will
# dezombify all of the child processes that we're ignoring because
# of the timeout.
Thread.new { Process.waitall }
return nil
rescue => details
warn "Could not retrieve %s: %s" % [self.name, details]
return nil
end
return nil if result == ""
return result
end
end
Jump to Line
Something went wrong with that request. Please try again.