Class: Puppet::Pops::Binder::BindingsComposer

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet/pops/binder/bindings_composer.rb

Overview

The BindingsComposer handles composition of multiple bindings sources It is directed by a 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).

Defined Under Namespace

Classes: SchemeHandlerHelper

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBindingsComposer

Returns a new instance of BindingsComposer.



39
40
41
42
43
44
45
46
47
# 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

Instance Attribute Details

#acceptorObject (readonly)

Container of all warnings and errors produced while initializing and loading bindings



36
37
38
# File 'lib/puppet/pops/binder/bindings_composer.rb', line 36

def acceptor
  @acceptor
end

#confdirObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



28
29
30
# File 'lib/puppet/pops/binder/bindings_composer.rb', line 28

def confdir
  @confdir
end

#configObject (readonly)

The BindingsConfig instance holding the read and parsed, but not evaluated configuration



17
18
19
# File 'lib/puppet/pops/binder/bindings_composer.rb', line 17

def config
  @config
end

#diagnosticsObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



31
32
33
# File 'lib/puppet/pops/binder/bindings_composer.rb', line 31

def diagnostics
  @diagnostics
end

#name_to_moduleHash{String => Puppet::Module} (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns map of module name to module instance.

Returns:



25
26
27
# File 'lib/puppet/pops/binder/bindings_composer.rb', line 25

def name_to_module
  @name_to_module
end

#scheme_handlersObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

map of scheme name to handler



21
22
23
# File 'lib/puppet/pops/binder/bindings_composer.rb', line 21

def scheme_handlers
  @scheme_handlers
end

Instance Method Details

#compose(scope) ⇒ Puppet::Pops::Binder::Bindings::LayeredBindings



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# 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

#configure_and_create_injector(scope) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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.

Parameters:

  • scope (Puppet::Parser:Scope)

    the scope (used to find compiler and injector for the environment)



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# 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