Class: Facter::Util::Resolution

Inherits:
Object
  • Object
show all
Defined in:
lib/facter/util/resolution.rb

Constant Summary

INTERPRETER =
Facter::Util::Config.is_windows? ? "cmd.exe" : "/bin/sh"

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Resolution) initialize(name)

Create a new resolution mechanism.



91
92
93
94
95
96
97
# File 'lib/facter/util/resolution.rb', line 91

def initialize(name)
    @name = name
    @confines = []
    @value = nil
    @timeout = 0
    @weight = nil
end

Instance Attribute Details

- (Object) code

Returns the value of attribute code



12
13
14
# File 'lib/facter/util/resolution.rb', line 12

def code
  @code
end

- (Object) interpreter

Returns the value of attribute interpreter



12
13
14
15
# File 'lib/facter/util/resolution.rb', line 12

def interpreter
  Facter.warnonce "The 'Facter::Util::Resolution.interpreter' method is deprecated and will be removed in a future version."
  @interpreter
end

- (Object) name

Returns the value of attribute name



12
13
14
# File 'lib/facter/util/resolution.rb', line 12

def name
  @name
end

- (Object) timeout

Returns the value of attribute timeout



12
13
14
# File 'lib/facter/util/resolution.rb', line 12

def timeout
  @timeout
end

Class Method Details

+ (Object) exec(code, interpreter = nil)

Execute a program and return the output of that program.

Returns nil if the program can't be found, or if there is a problem executing the code.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/facter/util/resolution.rb', line 33

def self.exec(code, interpreter = nil)
    Facter.warnonce "The interpreter parameter to 'exec' is deprecated and will be removed in a future version." if interpreter

    # Try to guess whether the specified code can be executed by looking at the
    # first word. If it cannot be found on the PATH defer on resolving the fact
    # by returning nil.
    # This only fails on shell built-ins, most of which are masked by stuff in 
    # /bin or of dubious value anyways. In the worst case, "sh -c 'builtin'" can
    # be used to work around this limitation
    #
    # Windows' %x{} throws Errno::ENOENT when the command is not found, so we 
    # can skip the check there. This is good, since builtins cannot be found 
    # elsewhere.
    if have_which and !Facter::Util::Config.is_windows?
        path = nil
        binary = code.split.first
        if code =~ /^\//
            path = binary
        else
            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\./)
        end

        return nil unless FileTest.exists?(path)
    end

    out = nil

    begin
        out = %x{#{code}}.chomp
    rescue Errno::ENOENT => detail
        # command not found on Windows
        return nil
    rescue => detail
        $stderr.puts detail
        return nil
    end

    if out == ""
        return nil
    else
        return out
    end
end

+ (Object) have_which



16
17
18
19
20
21
22
23
24
25
26
# File 'lib/facter/util/resolution.rb', line 16

def self.have_which
    if ! defined?(@have_which) or @have_which.nil?
        if Facter.value(:kernel) == 'windows'
            @have_which = false
        else
            %x{which which >/dev/null 2>&1}
            @have_which = ($? == 0)
        end
    end
    @have_which
end

Instance Method Details

- (Object) confine(confines)

Add a new confine to the resolution mechanism.



80
81
82
83
84
# File 'lib/facter/util/resolution.rb', line 80

def confine(confines)
    confines.each do |fact, values|
        @confines.push Facter::Util::Confine.new(fact, *values)
    end
end

- (Object) has_weight(weight)



86
87
88
# File 'lib/facter/util/resolution.rb', line 86

def has_weight(weight)
    @weight = weight
end

- (Object) limit

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.



111
112
113
# File 'lib/facter/util/resolution.rb', line 111

def limit
    @timeout
end

- (Object) setcode(string = nil, interp = nil, &block)

Set our code for returning a value.



116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/facter/util/resolution.rb', line 116

def setcode(string = nil, interp = nil, &block)
    Facter.warnonce "The interpreter parameter to 'setcode' is deprecated and will be removed in a future version." if interp
    if string
        @code = string
        @interpreter = interp || INTERPRETER
    else
        unless block_given?
            raise ArgumentError, "You must pass either code or a block"
        end
        @code = block
    end
end

- (Boolean) suitable?

Is this resolution mechanism suitable on the system in question?

Returns:

  • (Boolean)


140
141
142
143
144
145
146
# File 'lib/facter/util/resolution.rb', line 140

def suitable?
    unless defined? @suitable
        @suitable = ! @confines.detect { |confine| ! confine.true? }
    end

    return @suitable
end

- (Object) to_s



148
149
150
# File 'lib/facter/util/resolution.rb', line 148

def to_s
    return self.value()
end

- (Object) value

How we get a value for our resolution mechanism.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/facter/util/resolution.rb', line 153

def value
    result = nil
    return result if @code == nil

    starttime = Time.now.to_f

    begin
        Timeout.timeout(limit) do
            if @code.is_a?(Proc)
                result = @code.call()
            else
                result = Facter::Util::Resolution.exec(@code)
            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

    finishtime = Time.now.to_f
    ms = (finishtime - starttime) * 1000
    Facter.show_time "#{self.name}: #{"%.2f" % ms}ms"

    return nil if result == ""
    return result
end

- (Object) weight

Return the importance of this resolution.



100
101
102
103
104
105
106
# File 'lib/facter/util/resolution.rb', line 100

def weight
    if @weight
        @weight
    else
        @confines.length
    end
end