Class: Puppet::Util::Feature

Inherits:
Object
  • Object
show all
Includes:
Warnings
Defined in:
lib/puppet/util/feature.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Warnings

clear_warnings, debug_once, maybe_log, notice_once, warnonce

Constructor Details

#initialize(path) ⇒ Feature

Create a new feature collection.


64
65
66
67
68
# File 'lib/puppet/util/feature.rb', line 64

def initialize(path)
  @path = path
  @results = {}
  @loader = Puppet::Util::Autoload.new(self, @path)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object


74
75
76
77
78
79
80
81
# File 'lib/puppet/util/feature.rb', line 74

def method_missing(method, *args)
  return super unless method.to_s =~ /\?$/

  feature = method.to_s.sub(/\?$/, '')
  @loader.load(feature, Puppet.lookup(:current_environment))

  respond_to?(method) && self.send(method)
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path


7
8
9
# File 'lib/puppet/util/feature.rb', line 7

def path
  @path
end

Instance Method Details

#add(name, options = {}, &block) ⇒ Object

Create a new feature test. You have to pass the feature name, and it must be unique. You can pass a block to determine if the feature is present:

Puppet.features.add(:myfeature) do
  # return true or false if feature is available
  # return nil if feature may become available later
end

The block should return true if the feature is available, false if it is not, or nil if the state is unknown. True and false values will be cached. A nil value will not be cached, and should be used if the feature may become true in the future.

Features are often used to detect if a ruby library is installed. To support that common case, you can pass one or more ruby libraries, and the feature will be true if all of the libraries load successfully:

Puppet.features.add(:myfeature, libs: 'mylib')
Puppet.features.add(:myfeature, libs: ['mylib', 'myotherlib'])

If the ruby library is not installed, then the failure is not cached, as it's assumed puppet may install the gem during catalog application.

If a feature is defined using `:libs` and a block, then the block is used and the `:libs` are ignored.

Puppet evaluates the feature test when the `Puppet.features.myfeature?` method is called. If the feature test was defined using a block and the block returns nil, then the feature test will be re-evaluated the next time `Puppet.features.myfeature?` is called.


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/puppet/util/feature.rb', line 42

def add(name, options = {}, &block)
  method = name.to_s + "?"
  @results.delete(name)

  meta_def(method) do
    # we return a cached result if:
    #  * if we've tested this feature before
    #  AND
    #    * the result was true/false
    #    OR
    #    * we're configured to never retry
    if @results.has_key?(name) &&
       (!@results[name].nil? || !Puppet[:always_retry_plugins])
      !!@results[name]
    else
      @results[name] = test(name, options, &block)
      !!@results[name]
    end
  end
end

#loadObject


70
71
72
# File 'lib/puppet/util/feature.rb', line 70

def load
  @loader.loadall(Puppet.lookup(:current_environment))
end

#test(name, options, &block) ⇒ Object

Actually test whether the feature is present. We only want to test when someone asks for the feature, so we don't unnecessarily load files.


86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/puppet/util/feature.rb', line 86

def test(name, options, &block)
  if block_given?
    begin
      result = yield
    rescue StandardError,ScriptError => detail
      warn _("Failed to load feature test for %{name}: %{detail}") % { name: name, detail: detail }
      result = nil
    end
    @results[name] = result
    result
  else
    libs = options[:libs]
    if libs
      libs = [libs] unless libs.is_a?(Array)
      libs.all? { |lib| load_library(lib, name) } ? true : nil
    else
      true
    end
  end
end