class Puppet::Pops::Loaders

This is the container for all Loader instances. Each Loader instance has a `loader_name` by which it can be uniquely identified within this container. A Loader can be private or public. In general, code will have access to the private loader associated with the location of the code. It will be parented by a loader that in turn have access to other public loaders that can load only such entries that have been publicly available. The split between public and private is not yet enforced in Puppet.

The name of a private loader should always end with ' private'

Attributes

environment[R]
private_environment_loader[R]
public_environment_loader[R]
puppet_cache_loader[R]

Commented out the :static_loader and :puppet_system_loader because of rubocop offenses with duplicated definitions of these generated methods, but keeping them here for visibility on how the loaders are stacked. attr_reader :static_loader attr_reader :puppet_system_loader

Public Class Methods

catalog_loader() click to toggle source

Finds a loader to use when deserializing a catalog and then subsequenlty use user defined types found in that catalog.

    # File lib/puppet/pops/loaders.rb
166 def self.catalog_loader
167   loaders = Puppet.lookup(:loaders) { nil }
168   if loaders.nil?
169     loaders = Loaders.new(Puppet.lookup(:current_environment), true)
170     Puppet.push_context(:loaders => loaders)
171   end
172   loaders.find_loader(nil)
173 end
clear() click to toggle source

Clears the cached static and puppet_system loaders (to enable testing)

   # File lib/puppet/pops/loaders.rb
80 def self.clear
81   @@static_loader = nil
82   Puppet::Pops::Types::TypeFactory.clear
83   Model.class_variable_set(:@@pcore_ast_initialized, false)
84   Model.register_pcore_types
85 end
find_loader(module_name) click to toggle source

Calls {#loaders} to obtain the {{Loaders}} instance and then uses it to find the appropriate loader for the given `module_name`, or for the environment in case `module_name` is `nil` or empty.

@param module_name [String,nil] the name of the module @return [Loader::Loader] the found loader @raise [Puppet::ParseError] if no loader can be found @api private

   # File lib/puppet/pops/loaders.rb
94 def self.find_loader(module_name)
95   loaders.find_loader(module_name)
96 end
implementation_registry() click to toggle source
    # File lib/puppet/pops/loaders.rb
117 def self.implementation_registry
118   loaders = Puppet.lookup(:loaders) { nil }
119   loaders.nil? ? nil : loaders.implementation_registry
120 end
loaders() click to toggle source

Finds the `Loaders` instance by looking up the :loaders in the global Puppet context

@return [Loaders] the loaders instance @raise [Puppet::ParseError] if loader has been bound to the global context @api private

    # File lib/puppet/pops/loaders.rb
180 def self.loaders
181   loaders = Puppet.lookup(:loaders) { nil }
182   raise Puppet::ParseError, _("Internal Error: Puppet Context ':loaders' missing") if loaders.nil?
183   loaders
184 end
new(environment, for_agent = false, load_from_pcore = true) click to toggle source
   # File lib/puppet/pops/loaders.rb
26 def self.new(environment, for_agent = false, load_from_pcore = true)
27   environment.lock.synchronize do
28     obj = environment.loaders
29     if obj.nil?
30       obj = self.allocate
31       obj.send(:initialize, environment, for_agent, load_from_pcore)
32     end
33     obj
34   end
35 end
new(environment, for_agent, load_from_pcore = true) click to toggle source
   # File lib/puppet/pops/loaders.rb
37 def initialize(environment, for_agent, load_from_pcore = true)
38   # Protect against environment havoc
39   raise ArgumentError.new(_("Attempt to redefine already initialized loaders for environment")) unless environment.loaders.nil?
40   environment.loaders = self
41   @environment = environment
42   @loaders_by_name = {}
43 
44   add_loader_by_name(self.class.static_loader)
45 
46   # Create the set of loaders
47   # 1. Puppet, loads from the "running" puppet - i.e. bundled functions, types, extension points and extensions
48   #    These cannot be cached since a  loaded instance will be bound to its closure scope which holds on to
49   #    a compiler and all loaded types. Subsequent request would find remains of the environment that loaded
50   #    the content. PUP-4461.
51   #
52   @puppet_system_loader = create_puppet_system_loader()
53 
54   # 2. Cache loader(optional) - i.e. what puppet stores on disk via pluginsync; gate behind the for_agent flag.
55   # 3. Environment loader - i.e. what is bound across the environment, may change for each setup
56   #    TODO: loaders need to work when also running in an agent doing catalog application. There is no
57   #    concept of environment the same way as when running as a master (except when doing apply).
58   #    The creation mechanisms should probably differ between the two.
59   @private_environment_loader =
60     if for_agent
61       @puppet_cache_loader = create_puppet_cache_loader
62       create_environment_loader(environment, @puppet_cache_loader, load_from_pcore)
63     else
64       create_environment_loader(environment, @puppet_system_loader, load_from_pcore)
65     end
66 
67   Pcore.init_env(@private_environment_loader)
68 
69   # 4. module loaders are set up from the create_environment_loader, they register themselves
70 end
register_implementations_with_loader(obj_classes, name_authority, loader) click to toggle source
    # File lib/puppet/pops/loaders.rb
131 def self.register_implementations_with_loader(obj_classes, name_authority, loader)
132   types = obj_classes.map do |obj_class|
133     type = obj_class._pcore_type
134     typed_name = Loader::TypedName.new(:type, type.name, name_authority)
135     entry = loader.loaded_entry(typed_name)
136     loader.set_entry(typed_name, type) if entry.nil? || entry.value.nil?
137     type
138   end
139   # Resolve lazy so that all types can cross reference each other
140   types.each { |type| type.resolve(loader) }
141 end
register_runtime3_type(name, origin) click to toggle source

Register the given type with the Runtime3TypeLoader. The registration will not happen unless the type system has been initialized.

@param name [String,Symbol] the name of the entity being set @param origin [URI] the origin or the source where the type is defined @api private

    # File lib/puppet/pops/loaders.rb
149 def self.register_runtime3_type(name, origin)
150   loaders = Puppet.lookup(:loaders) { nil }
151   return nil if loaders.nil?
152 
153   rt3_loader = loaders.runtime3_type_loader
154   return nil if rt3_loader.nil?
155 
156   name = name.to_s
157   caps_name = Types::TypeFormatter.singleton.capitalize_segments(name)
158   typed_name = Loader::TypedName.new(:type, name)
159   rt3_loader.set_entry(typed_name, Types::PResourceType.new(caps_name), origin)
160   nil
161 end
register_static_implementations(obj_classes) click to toggle source

Register implementations using the global static loader

    # File lib/puppet/pops/loaders.rb
127 def self.register_static_implementations(obj_classes)
128   register_implementations_with_loader(obj_classes, Pcore::RUNTIME_NAME_AUTHORITY, static_loader)
129 end
static_implementation_registry() click to toggle source
    # File lib/puppet/pops/loaders.rb
 98 def self.static_implementation_registry
 99   if !class_variable_defined?(:@@static_implementation_registry) || @@static_implementation_registry.nil?
100     ir = Types::ImplementationRegistry.new
101     Types::TypeParser.type_map.values.each { |t| ir.register_implementation(t.simple_name, t.class.name) }
102     @@static_implementation_registry = ir
103   end
104   @@static_implementation_registry
105 end
static_loader() click to toggle source
    # File lib/puppet/pops/loaders.rb
107 def self.static_loader
108   # The static loader can only be changed after a reboot
109   if !class_variable_defined?(:@@static_loader) || @@static_loader.nil?
110     @@static_loader = Loader::StaticLoader.new()
111     @@static_loader.register_aliases
112     Pcore.init(@@static_loader, static_implementation_registry)
113   end
114   @@static_loader
115 end

Public Instance Methods

[](loader_name) click to toggle source

Lookup a loader by its unique name.

@param [String] loader_name the name of the loader to lookup @return [Loader] the found loader @raise [Puppet::ParserError] if no loader is found

    # File lib/puppet/pops/loaders.rb
191 def [](loader_name)
192   loader = @loaders_by_name[loader_name]
193   if loader.nil?
194     # Unable to find the module private loader. Try resolving the module
195     loader = private_loader_for_module(loader_name[0..-9]) if loader_name.end_with?(' private')
196     raise Puppet::ParseError, _("Unable to find loader named '%{loader_name}'") % { loader_name: loader_name } if loader.nil?
197   end
198   loader
199 end
add_loader_by_name(loader) click to toggle source
    # File lib/puppet/pops/loaders.rb
260 def add_loader_by_name(loader)
261   name = loader.loader_name
262   if @loaders_by_name.include?(name)
263     raise Puppet::ParseError, _("Internal Error: Attempt to redefine loader named '%{name}'") % { name: name }
264   end
265   @loaders_by_name[name] = loader
266 end
find_loader(module_name) click to toggle source

Finds the appropriate loader for the given `module_name`, or for the environment in case `module_name` is `nil` or empty.

@param module_name [String,nil] the name of the module @return [Loader::Loader] the found loader @raise [Puppet::ParseError] if no loader can be found @api private

    # File lib/puppet/pops/loaders.rb
208 def find_loader(module_name)
209   if module_name.nil? || EMPTY_STRING == module_name
210     # Use the public environment loader
211     public_environment_loader
212   else
213     # TODO : Later check if definition is private, and then add it to private_loader_for_module
214     #
215     loader = public_loader_for_module(module_name)
216     if loader.nil?
217       raise Puppet::ParseError, _("Internal Error: did not find public loader for module: '%{module_name}'") % { module_name: module_name }
218     end
219     loader
220   end
221 end
implementation_registry() click to toggle source
    # File lib/puppet/pops/loaders.rb
223 def implementation_registry
224   # Environment specific implementation registry
225   @implementation_registry ||= Types::ImplementationRegistry.new(self.class.static_implementation_registry)
226 end
instantiate_definition(definition, loader) click to toggle source

Add given 4.x definition to the given loader.

    # File lib/puppet/pops/loaders.rb
319 def instantiate_definition(definition, loader)
320   case definition
321   when Model::PlanDefinition
322     instantiate_PlanDefinition(definition, loader)
323   when Model::FunctionDefinition
324     instantiate_FunctionDefinition(definition, loader)
325   when Model::TypeAlias
326     instantiate_TypeAlias(definition, loader)
327   when Model::TypeMapping
328     instantiate_TypeMapping(definition, loader)
329   else
330     raise Puppet::ParseError, "Internal Error: Unknown type of definition - got '#{definition.class}'"
331   end
332 end
instantiate_definitions(program, loader) click to toggle source

Add 4.x definitions found in the given program to the given loader.

    # File lib/puppet/pops/loaders.rb
313 def instantiate_definitions(program, loader)
314   program.definitions.each { |d| instantiate_definition(d, loader) }
315   nil
316 end
load_main_manifest() click to toggle source

Load the main manifest for the given environment

There are two sources that can be used for the initial parse:

1. The value of `Puppet[:code]`: Puppet can take a string from
  its settings and parse that as a manifest. This is used by various
  Puppet applications to read in a manifest and pass it to the
  environment as a side effect. This is attempted first.
2. The contents of the environment's +manifest+ attribute: Puppet will
  try to load the environment manifest. The manifest must be a file.

@return [Model::Program] The manifest parsed into a model object

    # File lib/puppet/pops/loaders.rb
280 def load_main_manifest
281   parser = Parser::EvaluatingParser.singleton
282   parsed_code = Puppet[:code]
283   program = if parsed_code != ""
284     parser.parse_string(parsed_code, 'unknown-source-location')
285   else
286     file = @environment.manifest
287 
288     # if the manifest file is a reference to a directory, parse and combine
289     # all .pp files in that directory
290     if file == Puppet::Node::Environment::NO_MANIFEST
291       nil
292     elsif File.directory?(file)
293       raise Puppet::Error, "manifest of environment '#{@environment.name}' appoints directory '#{file}'. It must be a file"
294     elsif File.exist?(file)
295       parser.parse_file(file)
296     else
297       raise Puppet::Error, "manifest of environment '#{@environment.name}' appoints '#{file}'. It does not exist"
298     end
299   end
300   instantiate_definitions(program, public_environment_loader) unless program.nil?
301   program
302 rescue Puppet::ParseErrorWithIssue => detail
303   detail.environment = @environment.name
304   raise
305 rescue => detail
306   msg = _('Could not parse for environment %{env}: %{detail}') % { env: @environment, detail: detail }
307   error = Puppet::Error.new(msg)
308   error.set_backtrace(detail.backtrace)
309   raise error
310 end
pre_load() click to toggle source

Called after loader has been added to Puppet Context as :loaders so that dynamic types can be pre-loaded with a fully configured loader system

   # File lib/puppet/pops/loaders.rb
74 def pre_load
75   @puppet_system_loader.load(:type, 'error')
76 end
private_loader_for_module(module_name) click to toggle source
    # File lib/puppet/pops/loaders.rb
249 def private_loader_for_module(module_name)
250   md = @module_resolver[module_name] || (return nil)
251   # Since there is interest in the visibility from the perspective of entities contained in the
252   # module, it must be resolved (to provide this visibility).
253   # See {#configure_loaders_for_modules}
254   unless md.resolved?
255     @module_resolver.resolve(md)
256   end
257   md.private_loader
258 end
public_loader_for_module(module_name) click to toggle source
    # File lib/puppet/pops/loaders.rb
240 def public_loader_for_module(module_name)
241   md = @module_resolver[module_name] || (return nil)
242   # Note, this loader is not resolved until there is interest in the visibility of entities from the
243   # perspective of something contained in the module. (Many request may pass through a module loader
244   # without it loading anything.
245   # See {#private_loader_for_module}, and not in {#configure_loaders_for_modules}
246   md.public_loader
247 end
puppet_system_loader() click to toggle source
    # File lib/puppet/pops/loaders.rb
232 def puppet_system_loader
233   @puppet_system_loader
234 end
register_implementations(obj_classes, name_authority) click to toggle source
    # File lib/puppet/pops/loaders.rb
122 def register_implementations(obj_classes, name_authority)
123   self.class.register_implementations_with_loader(obj_classes, name_authority, @private_environment_loader)
124 end
runtime3_type_loader() click to toggle source
    # File lib/puppet/pops/loaders.rb
236 def runtime3_type_loader
237   @runtime3_type_loader
238 end
static_loader() click to toggle source
    # File lib/puppet/pops/loaders.rb
228 def static_loader
229   self.class.static_loader
230 end

Private Instance Methods

configure_loaders_for_modules(parent_loader, environment) click to toggle source
    # File lib/puppet/pops/loaders.rb
431 def configure_loaders_for_modules(parent_loader, environment)
432   @module_resolver = mr = ModuleResolver.new(self)
433   environment.modules.each do |puppet_module|
434     # Create data about this module
435     md = LoaderModuleData.new(puppet_module)
436     mr[puppet_module.name] = md
437     md.public_loader = Loader::ModuleLoaders.module_loader_from(parent_loader, self, md.name, md.path)
438   end
439   # NOTE: Do not resolve all modules here - this is wasteful if only a subset of modules / functions are used
440   #       The resolution is triggered by asking for a module's private loader, since this means there is interest
441   #       in the visibility from that perspective.
442   #       If later, it is wanted that all resolutions should be made up-front (to capture errors eagerly, this
443   #       can be introduced (better for production), but may be irritating in development mode.
444 end
create_environment_loader(environment, parent_loader, load_from_pcore = true) click to toggle source
    # File lib/puppet/pops/loaders.rb
371 def create_environment_loader(environment, parent_loader, load_from_pcore = true)
372   # This defines where to start parsing/evaluating - the "initial import" (to use 3x terminology)
373   # Is either a reference to a single .pp file, or a directory of manifests. If the environment becomes
374   # a module and can hold functions, types etc. then these are available across all other modules without
375   # them declaring this dependency - it is however valuable to be able to treat it the same way
376   # bindings and other such system related configuration.
377 
378   # This is further complicated by the many options available:
379   # - The environment may not have a directory, the code comes from one appointed 'manifest' (site.pp)
380   # - The environment may have a directory and also point to a 'manifest'
381   # - The code to run may be set in settings (code)
382 
383   # Further complication is that there is nothing specifying what the visibility is into
384   # available modules. (3x is everyone sees everything).
385   # Puppet binder currently reads confdir/bindings - that is bad, it should be using the new environment support.
386 
387   # env_conf is setup from the environment_dir value passed into Puppet::Environments::Directories.new
388   env_conf = Puppet.lookup(:environments).get_conf(environment.name)
389   env_path = env_conf.nil? || !env_conf.is_a?(Puppet::Settings::EnvironmentConf) ? nil : env_conf.path_to_env
390 
391   if Puppet[:tasks]
392     loader = Loader::ModuleLoaders.environment_loader_from(parent_loader, self, env_path)
393   else
394     # Create the 3.x resource type loader
395     static_loader.runtime_3_init
396     # Create pcore resource type loader, if applicable
397     pcore_resource_type_loader = if load_from_pcore && env_path
398                                    Loader::ModuleLoaders.pcore_resource_type_loader_from(parent_loader, self, env_path)
399                                  else
400                                    nil
401                                  end
402     @runtime3_type_loader = add_loader_by_name(Loader::Runtime3TypeLoader.new(parent_loader, self, environment, pcore_resource_type_loader))
403 
404     if env_path.nil?
405       # Not a real directory environment, cannot work as a module TODO: Drop when legacy env are dropped?
406       loader = add_loader_by_name(Loader::SimpleEnvironmentLoader.new(@runtime3_type_loader, Loader::ENVIRONMENT, environment))
407     else
408       # View the environment as a module to allow loading from it - this module is always called 'environment'
409       loader = Loader::ModuleLoaders.environment_loader_from(@runtime3_type_loader, self, env_path)
410     end
411   end
412 
413   # An environment has a module path even if it has a null loader
414   configure_loaders_for_modules(loader, environment)
415   # modules should see this loader
416   @public_environment_loader = loader
417 
418   # Code in the environment gets to see all modules (since there is no metadata for the environment)
419   # but since this is not given to the module loaders, they can not load global code (since they can not
420   # have prior knowledge about this
421   loader = add_loader_by_name(Loader::DependencyLoader.new(loader, Loader::ENVIRONMENT_PRIVATE, @module_resolver.all_module_loaders(), environment))
422 
423   # The module loader gets the private loader via a lazy operation to look up the module's private loader.
424   # This does not work for an environment since it is not resolved the same way.
425   # TODO: The EnvironmentLoader could be a specialized loader instead of using a ModuleLoader to do the work.
426   #       This is subject to future design - an Environment may move more in the direction of a Module.
427   @public_environment_loader.private_loader = loader
428   loader
429 end
create_puppet_cache_loader() click to toggle source
    # File lib/puppet/pops/loaders.rb
367 def create_puppet_cache_loader()
368   Loader::ModuleLoaders.cached_loader_from(puppet_system_loader, self)
369 end
create_puppet_system_loader() click to toggle source
    # File lib/puppet/pops/loaders.rb
363 def create_puppet_system_loader()
364   Loader::ModuleLoaders.system_loader_from(static_loader, self)
365 end
instantiate_FunctionDefinition(function_definition, loader) click to toggle source
    # File lib/puppet/pops/loaders.rb
342 def instantiate_FunctionDefinition(function_definition, loader)
343   # Instantiate Function, and store it in the loader
344   typed_name, f = Loader::PuppetFunctionInstantiator.create_from_model(function_definition, loader)
345   loader.set_entry(typed_name, f, function_definition.locator.to_uri(function_definition))
346   nil
347 end
instantiate_PlanDefinition(plan_definition, loader) click to toggle source
    # File lib/puppet/pops/loaders.rb
336 def instantiate_PlanDefinition(plan_definition, loader)
337   typed_name, f = Loader::PuppetPlanInstantiator.create_from_model(plan_definition, loader)
338   loader.set_entry(typed_name, f, plan_definition.locator.to_uri(plan_definition))
339   nil
340 end
instantiate_TypeAlias(type_alias, loader) click to toggle source
    # File lib/puppet/pops/loaders.rb
349 def instantiate_TypeAlias(type_alias, loader)
350   # Bind the type alias to the loader using the alias
351   Puppet::Pops::Loader::TypeDefinitionInstantiator.create_from_model(type_alias, loader)
352   nil
353 end
instantiate_TypeMapping(type_mapping, loader) click to toggle source
    # File lib/puppet/pops/loaders.rb
355 def instantiate_TypeMapping(type_mapping, loader)
356   tf = Types::TypeParser.singleton
357   lhs = tf.interpret(type_mapping.type_expr, loader)
358   rhs = tf.interpret_any(type_mapping.mapping_expr, loader)
359   implementation_registry.register_type_mapping(lhs, rhs)
360   nil
361 end