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]
puppet_system_loader[R]
static_loader[R]

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
161 def self.catalog_loader
162   loaders = Puppet.lookup(:loaders) { nil }
163   if loaders.nil?
164     loaders = Loaders.new(Puppet.lookup(:current_environment), true)
165     Puppet.push_context(:loaders => loaders)
166   end
167   loaders.find_loader(nil)
168 end
clear() click to toggle source

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

   # File lib/puppet/pops/loaders.rb
75 def self.clear
76   @@static_loader = nil
77   Puppet::Pops::Types::TypeFactory.clear
78   Model.class_variable_set(:@@pcore_ast_initialized, false)
79   Model.register_pcore_types
80 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
89 def self.find_loader(module_name)
90   loaders.find_loader(module_name)
91 end
implementation_registry() click to toggle source
    # File lib/puppet/pops/loaders.rb
112 def self.implementation_registry
113   loaders = Puppet.lookup(:loaders) { nil }
114   loaders.nil? ? nil : loaders.implementation_registry
115 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
175 def self.loaders
176   loaders = Puppet.lookup(:loaders) { nil }
177   raise Puppet::ParseError, _("Internal Error: Puppet Context ':loaders' missing") if loaders.nil?
178   loaders
179 end
new(environment, for_agent = false, load_from_pcore = true) click to toggle source
   # File lib/puppet/pops/loaders.rb
21 def self.new(environment, for_agent = false, load_from_pcore = true)
22   environment.lock.synchronize do
23     obj = environment.loaders
24     if obj.nil?
25       obj = self.allocate
26       obj.send(:initialize, environment, for_agent, load_from_pcore)
27     end
28     obj
29   end
30 end
new(environment, for_agent, load_from_pcore = true) click to toggle source
   # File lib/puppet/pops/loaders.rb
32 def initialize(environment, for_agent, load_from_pcore = true)
33   # Protect against environment havoc
34   raise ArgumentError.new(_("Attempt to redefine already initialized loaders for environment")) unless environment.loaders.nil?
35   environment.loaders = self
36   @environment = environment
37   @loaders_by_name = {}
38 
39   add_loader_by_name(self.class.static_loader)
40 
41   # Create the set of loaders
42   # 1. Puppet, loads from the "running" puppet - i.e. bundled functions, types, extension points and extensions
43   #    These cannot be cached since a  loaded instance will be bound to its closure scope which holds on to
44   #    a compiler and all loaded types. Subsequent request would find remains of the environment that loaded
45   #    the content. PUP-4461.
46   #
47   @puppet_system_loader = create_puppet_system_loader()
48 
49   # 2. Cache loader(optional) - i.e. what puppet stores on disk via pluginsync; gate behind the for_agent flag.
50   # 3. Environment loader - i.e. what is bound across the environment, may change for each setup
51   #    TODO: loaders need to work when also running in an agent doing catalog application. There is no
52   #    concept of environment the same way as when running as a master (except when doing apply).
53   #    The creation mechanisms should probably differ between the two.
54   @private_environment_loader =
55     if for_agent
56       @puppet_cache_loader = create_puppet_cache_loader
57       create_environment_loader(environment, @puppet_cache_loader, load_from_pcore)
58     else
59       create_environment_loader(environment, @puppet_system_loader, load_from_pcore)
60     end
61 
62   Pcore.init_env(@private_environment_loader)
63 
64   # 4. module loaders are set up from the create_environment_loader, they register themselves
65 end
register_implementations_with_loader(obj_classes, name_authority, loader) click to toggle source
    # File lib/puppet/pops/loaders.rb
126 def self.register_implementations_with_loader(obj_classes, name_authority, loader)
127   types = obj_classes.map do |obj_class|
128     type = obj_class._pcore_type
129     typed_name = Loader::TypedName.new(:type, type.name, name_authority)
130     entry = loader.loaded_entry(typed_name)
131     loader.set_entry(typed_name, type) if entry.nil? || entry.value.nil?
132     type
133   end
134   # Resolve lazy so that all types can cross reference each other
135   types.each { |type| type.resolve(loader) }
136 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
144 def self.register_runtime3_type(name, origin)
145   loaders = Puppet.lookup(:loaders) { nil }
146   return nil if loaders.nil?
147 
148   rt3_loader = loaders.runtime3_type_loader
149   return nil if rt3_loader.nil?
150 
151   name = name.to_s
152   caps_name = Types::TypeFormatter.singleton.capitalize_segments(name)
153   typed_name = Loader::TypedName.new(:type, name)
154   rt3_loader.set_entry(typed_name, Types::PResourceType.new(caps_name), origin)
155   nil
156 end
register_static_implementations(obj_classes) click to toggle source

Register implementations using the global static loader

    # File lib/puppet/pops/loaders.rb
122 def self.register_static_implementations(obj_classes)
123   register_implementations_with_loader(obj_classes, Pcore::RUNTIME_NAME_AUTHORITY, static_loader)
124 end
static_implementation_registry() click to toggle source
    # File lib/puppet/pops/loaders.rb
 93 def self.static_implementation_registry
 94   if !class_variable_defined?(:@@static_implementation_registry) || @@static_implementation_registry.nil?
 95     ir = Types::ImplementationRegistry.new
 96     Types::TypeParser.type_map.values.each { |t| ir.register_implementation(t.simple_name, t.class.name) }
 97     @@static_implementation_registry = ir
 98   end
 99   @@static_implementation_registry
100 end
static_loader() click to toggle source
    # File lib/puppet/pops/loaders.rb
102 def self.static_loader
103   # The static loader can only be changed after a reboot
104   if !class_variable_defined?(:@@static_loader) || @@static_loader.nil?
105     @@static_loader = Loader::StaticLoader.new()
106     @@static_loader.register_aliases
107     Pcore.init(@@static_loader, static_implementation_registry)
108   end
109   @@static_loader
110 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
186 def [](loader_name)
187   loader = @loaders_by_name[loader_name]
188   if loader.nil?
189     # Unable to find the module private loader. Try resolving the module
190     loader = private_loader_for_module(loader_name[0..-9]) if loader_name.end_with?(' private')
191     raise Puppet::ParseError, _("Unable to find loader named '%{loader_name}'") % { loader_name: loader_name } if loader.nil?
192   end
193   loader
194 end
add_loader_by_name(loader) click to toggle source
    # File lib/puppet/pops/loaders.rb
255 def add_loader_by_name(loader)
256   name = loader.loader_name
257   if @loaders_by_name.include?(name)
258     raise Puppet::ParseError, _("Internal Error: Attempt to redefine loader named '%{name}'") % { name: name }
259   end
260   @loaders_by_name[name] = loader
261 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
203 def find_loader(module_name)
204   if module_name.nil? || EMPTY_STRING == module_name
205     # Use the public environment loader
206     public_environment_loader
207   else
208     # TODO : Later check if definition is private, and then add it to private_loader_for_module
209     #
210     loader = public_loader_for_module(module_name)
211     if loader.nil?
212       raise Puppet::ParseError, _("Internal Error: did not find public loader for module: '%{module_name}'") % { module_name: module_name }
213     end
214     loader
215   end
216 end
implementation_registry() click to toggle source
    # File lib/puppet/pops/loaders.rb
218 def implementation_registry
219   # Environment specific implementation registry
220   @implementation_registry ||= Types::ImplementationRegistry.new(self.class.static_implementation_registry)
221 end
instantiate_definition(definition, loader) click to toggle source

Add given 4.x definition to the given loader.

    # File lib/puppet/pops/loaders.rb
314 def instantiate_definition(definition, loader)
315   case definition
316   when Model::PlanDefinition
317     instantiate_PlanDefinition(definition, loader)
318   when Model::FunctionDefinition
319     instantiate_FunctionDefinition(definition, loader)
320   when Model::TypeAlias
321     instantiate_TypeAlias(definition, loader)
322   when Model::TypeMapping
323     instantiate_TypeMapping(definition, loader)
324   else
325     raise Puppet::ParseError, "Internal Error: Unknown type of definition - got '#{definition.class}'"
326   end
327 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
308 def instantiate_definitions(program, loader)
309   program.definitions.each { |d| instantiate_definition(d, loader) }
310   nil
311 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
275 def load_main_manifest
276   parser = Parser::EvaluatingParser.singleton
277   parsed_code = Puppet[:code]
278   program = if parsed_code != ""
279     parser.parse_string(parsed_code, 'unknown-source-location')
280   else
281     file = @environment.manifest
282 
283     # if the manifest file is a reference to a directory, parse and combine
284     # all .pp files in that directory
285     if file == Puppet::Node::Environment::NO_MANIFEST
286       nil
287     elsif File.directory?(file)
288       raise Puppet::Error, "manifest of environment '#{@environment.name}' appoints directory '#{file}'. It must be a file"
289     elsif File.exist?(file)
290       parser.parse_file(file)
291     else
292       raise Puppet::Error, "manifest of environment '#{@environment.name}' appoints '#{file}'. It does not exist"
293     end
294   end
295   instantiate_definitions(program, public_environment_loader) unless program.nil?
296   program
297 rescue Puppet::ParseErrorWithIssue => detail
298   detail.environment = @environment.name
299   raise
300 rescue => detail
301   msg = _('Could not parse for environment %{env}: %{detail}') % { env: @environment, detail: detail }
302   error = Puppet::Error.new(msg)
303   error.set_backtrace(detail.backtrace)
304   raise error
305 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
69 def pre_load
70   @puppet_system_loader.load(:type, 'error')
71 end
private_loader_for_module(module_name) click to toggle source
    # File lib/puppet/pops/loaders.rb
244 def private_loader_for_module(module_name)
245   md = @module_resolver[module_name] || (return nil)
246   # Since there is interest in the visibility from the perspective of entities contained in the
247   # module, it must be resolved (to provide this visibility).
248   # See {#configure_loaders_for_modules}
249   unless md.resolved?
250     @module_resolver.resolve(md)
251   end
252   md.private_loader
253 end
public_loader_for_module(module_name) click to toggle source
    # File lib/puppet/pops/loaders.rb
235 def public_loader_for_module(module_name)
236   md = @module_resolver[module_name] || (return nil)
237   # Note, this loader is not resolved until there is interest in the visibility of entities from the
238   # perspective of something contained in the module. (Many request may pass through a module loader
239   # without it loading anything.
240   # See {#private_loader_for_module}, and not in {#configure_loaders_for_modules}
241   md.public_loader
242 end
register_implementations(obj_classes, name_authority) click to toggle source
    # File lib/puppet/pops/loaders.rb
117 def register_implementations(obj_classes, name_authority)
118   self.class.register_implementations_with_loader(obj_classes, name_authority, @private_environment_loader)
119 end
runtime3_type_loader() click to toggle source
    # File lib/puppet/pops/loaders.rb
231 def runtime3_type_loader
232   @runtime3_type_loader
233 end

Private Instance Methods

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