The BindingsComposer handles composition of multiple bindings sources It is directed by a {Puppet::Pops::Binder::Config::BinderConfig BinderConfig} that indicates how the final composition should be layered, and what should be included/excluded in each layer
The bindings composer is intended to be used once per environment as the compiler starts its work.
TODO: Possibly support envdir: scheme / relative to environment root (== same as confdir if there is only one environment).
This is probably easier to do after ENC changes described in ARM-8 have been implemented.
TODO: If same config is loaded in a higher layer, skip it in the lower (since it is meaningless to load it again with lower
precedence. (Optimization, or possibly an error, should produce a warning).
Container of all warnings and errors produced while initializing and loading bindings
@api public
@api private
The BindingsConfig instance holding the read and parsed, but not evaluated configuration @api public
@api private
@return [Hash{String => Puppet::Module}] map of module name to module instance @api private
map of scheme name to handler @api private
@return [Puppet::Pops::Binder::Bindings::LayeredBindings]
# File lib/puppet/pops/binder/bindings_composer.rb, line 84 def compose(scope) # The boot injector is used to lookup scheme-handlers configure_and_create_injector(scope) # get all existing modules and their root path @name_to_module = {} scope.environment.modules.each {|mod| name_to_module[mod.name] = mod } # setup the confdir @confdir = Puppet.settings[:confdir] factory = Puppet::Pops::Binder::BindingsFactory contributions = [] configured_layers = @config.layering_config.collect do | layer_config | # get contributions contribs = configure_layer(layer_config, scope, diagnostics) # collect the contributions separately for later checking of category precedence contributions.concat(contribs) # create a named layer with all the bindings for this layer factory.named_layer(layer_config['name'], *contribs.collect {|c| c.bindings }.flatten) end # Add the two system layers; the final - highest ("can not be overridden" layer), and the lowest # Everything here can be overridden 'default' layer. # configured_layers.insert(0, Puppet::Pops::Binder::SystemBindings.final_contribution) configured_layers.insert(-1, Puppet::Pops::Binder::SystemBindings.default_contribution) # and finally... create the resulting structure factory.layered_bindings(*configured_layers) end
Configures and creates the boot injector. The read config may optionally contain mapping of bindings scheme handler name to handler class, and mapping of biera2 backend symbolic name to backend class. If present, these are turned into bindings in the category ‘extension’ (which is only used in the boot injector) which has higher precedence than ‘default’. This is done to allow users to override the default bindings for schemes and backends. @param scope [Puppet::Parser:Scope] the scope (used to find compiler and injector for the environment) @api private
# File lib/puppet/pops/binder/bindings_composer.rb, line 58 def configure_and_create_injector(scope) # create the injector (which will pick up the bindings registered above) @scheme_handlers = SchemeHandlerHelper.new(scope) # get extensions from the config # ------------------------------ scheme_extensions = @config.scheme_extensions # Define a named bindings that are known by the SystemBindings boot_bindings = Puppet::Pops::Binder::BindingsFactory.named_bindings(Puppet::Pops::Binder::SystemBindings::ENVIRONMENT_BOOT_BINDINGS_NAME) do scheme_extensions.each_pair do |scheme, class_name| # turn each scheme => class_name into a binding (contribute to the buildings-schemes multibind). # do this in category 'extensions' to allow them to override the 'default' bind do name(scheme) instance_of(::Puppetx::BINDINGS_SCHEMES_TYPE) in_multibind(::Puppetx::BINDINGS_SCHEMES) to_instance(class_name) end end end @injector = scope.compiler.create_boot_injector(boot_bindings.model) end
@api public
# File lib/puppet/pops/binder/bindings_composer.rb, line 39 def initialize() @acceptor = Puppet::Pops::Validation::Acceptor.new() @diagnostics = Puppet::Pops::Binder::Config::DiagnosticProducer.new(acceptor) @config = Puppet::Pops::Binder::Config::BinderConfig.new(@diagnostics) if acceptor.errors? Puppet::Pops::IssueReporter.assert_and_report(acceptor, :message => 'Binding Composer: error while reading config.') raise Puppet::DevError.new("Internal Error: IssueReporter did not raise exception for errors in bindings config.") end end