Class: Puppet::Node::Environment

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet/node/environment.rb

Overview

Puppet::Node::Environment acts as a container for all configuration that is expected to vary between environments.

## The root environment

In addition to normal environments that are defined by the user,there is a special 'root' environment. It is defined as an instance variable on the Puppet::Node::Environment metaclass. The environment name is `root` and can be accessed by looking up the `:root_environment` using Puppet.lookup.

The primary purpose of the root environment is to contain parser functions that are not bound to a specific environment. The main case for this is for logging functions. Logging functions are attached to the 'root' environment when Parser::Functions.reset is called.

Direct Known Subclasses

None, Remote

Defined Under Namespace

Classes: None, Remote

Constant Summary collapse

NO_MANIFEST =
:no_manifest

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, modulepath, manifest, config_version) ⇒ Environment

Note:

new is private for historical reasons, as previously it had been overridden to return memoized objects and was replaced with create, so this will not be invoked with the normal Ruby initialization semantics.

Instantiate a new environment


73
74
75
76
77
78
79
80
# File 'lib/puppet/node/environment.rb', line 73

def initialize(name, modulepath, manifest, config_version)
  @lock = Puppet::Concurrent::Lock.new
  @name = name.intern
  @modulepath = self.class.expand_dirs(self.class.extralibs() + modulepath)
  @manifest = manifest == NO_MANIFEST ? manifest : Puppet::FileSystem.expand_path(manifest)

  @config_version = config_version
end

Instance Attribute Details

#config_versionObject (readonly)

Returns the value of attribute config_version


159
160
161
# File 'lib/puppet/node/environment.rb', line 159

def config_version
  @config_version
end

#loadersObject

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.

Cached loaders - management of value handled by Puppet::Pops::Loaders


163
164
165
# File 'lib/puppet/node/environment.rb', line 163

def loaders
  @loaders
end

#lockObject (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.

Lock for compilation that needs exclusive access to the environment


167
168
169
# File 'lib/puppet/node/environment.rb', line 167

def lock
  @lock
end

#manifestObject (readonly)

Returns the value of attribute manifest


153
154
155
# File 'lib/puppet/node/environment.rb', line 153

def manifest
  @manifest
end

#nameObject (readonly)

Returns the value of attribute name


134
135
136
# File 'lib/puppet/node/environment.rb', line 134

def name
  @name
end

Class Method Details

.create(name, modulepath, manifest = NO_MANIFEST, config_version = nil) ⇒ Puppet::Node::Environment

Create a new environment with the given name


42
43
44
# File 'lib/puppet/node/environment.rb', line 42

def self.create(name, modulepath, manifest = NO_MANIFEST, config_version = nil)
  new(name, modulepath, manifest, config_version)
end

.expand_dirs(dirs) ⇒ Object

not private so it can be called in initialize


509
510
511
512
513
# File 'lib/puppet/node/environment.rb', line 509

def self.expand_dirs(dirs)
  dirs.collect do |dir|
    Puppet::FileSystem.expand_path(dir)
  end
end

.extralibsObject

not private so it can be called in tests


500
501
502
503
504
505
506
# File 'lib/puppet/node/environment.rb', line 500

def self.extralibs()
  if Puppet::Util.get_env('PUPPETLIB')
    split_path(Puppet::Util.get_env('PUPPETLIB'))
  else
    []
  end
end

.remote(name) ⇒ Object

Note:

This does not provide access to the information of the remote

A “reference” to a remote environment. The created environment instance isn't expected to exist on the local system, but is instead a reference to environment information on a remote system. For instance when a catalog is being applied, this will be used on the agent.

environment's modules, manifest, or anything else. It is simply a value object to pass around and use as an environment.


61
62
63
# File 'lib/puppet/node/environment.rb', line 61

def self.remote(name)
  Remote.create(name, [], NO_MANIFEST)
end

.split_path(path_string) ⇒ Object


482
483
484
# File 'lib/puppet/node/environment.rb', line 482

def self.split_path(path_string)
  path_string.split(File::PATH_SEPARATOR)
end

.valid_name?(name) ⇒ Boolean

Returns true if name is valid.


126
127
128
# File 'lib/puppet/node/environment.rb', line 126

def self.valid_name?(name)
  !!name.match(/\A\w+\Z/)
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?


486
487
488
489
490
491
# File 'lib/puppet/node/environment.rb', line 486

def ==(other)
  return true if other.kind_of?(Puppet::Node::Environment) &&
    self.name == other.name &&
    self.full_modulepath == other.full_modulepath &&
    self.manifest == other.manifest
end

#[](param) ⇒ Object

Return an environment-specific Puppet setting.


234
235
236
# File 'lib/puppet/node/environment.rb', line 234

def [](param)
  Puppet.settings.value(param, self.name)
end

#check_for_reparseObject

Checks if a reparse is required (cache of files is stale).


445
446
447
448
449
450
451
452
# File 'lib/puppet/node/environment.rb', line 445

def check_for_reparse
  @lock.synchronize do
    if (Puppet[:code] != @parsed_code || @known_resource_types.parse_failed?)
      @parsed_code = nil
      @known_resource_types = nil
    end
  end
end

#configurationPuppet::Settings::EnvironmentConf

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.

Return the environment configuration


202
203
204
# File 'lib/puppet/node/environment.rb', line 202

def configuration
  Puppet.lookup(:environments).get_conf(name)
end

#conflicting_manifest_settings?Boolean

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.

Checks to make sure that this environment did not have a manifest set in its original environment.conf if Puppet is configured with disable_per_environment_manifest set true. If it did, the environment's modules may not function as intended by the original authors, and we may seek to halt a puppet compilation for a node in this environment.

The only exception to this would be if the environment.conf manifest is an exact, uninterpolated match for the current default_manifest setting.


183
184
185
186
187
# File 'lib/puppet/node/environment.rb', line 183

def conflicting_manifest_settings?
  return false if !Puppet[:disable_per_environment_manifest]
  original_manifest = configuration.raw_setting(:manifest)
  !original_manifest.nil? && !original_manifest.empty? && original_manifest != Puppet[:default_manifest]
end

#each_plugin_directory {|String| ... } ⇒ Object

Yields each modules' plugin directory if the plugin directory (modulename/lib) is present on the filesystem.

Yields:

  • (String)

    Yields the plugin directory from each module to the block.


255
256
257
258
259
260
# File 'lib/puppet/node/environment.rb', line 255

def each_plugin_directory(&block)
  modules.map(&:plugin_directory).each do |lib|
    lib = Puppet::Util::Autoload.cleanpath(lib)
    yield lib if File.directory?(lib)
  end
end

#full_modulepathArray<String>

Returns All directories in the modulepath (even if they are not present on disk).


146
147
148
# File 'lib/puppet/node/environment.rb', line 146

def full_modulepath
  @modulepath
end

#hashObject


495
496
497
# File 'lib/puppet/node/environment.rb', line 495

def hash
  [self.class, name, full_modulepath, manifest].hash
end

#inspectObject


467
468
469
# File 'lib/puppet/node/environment.rb', line 467

def inspect
  %Q{<#{self.class}:#{self.object_id} @name="#{name}" @manifest="#{manifest}" @modulepath="#{full_modulepath.join(":")}" >}
end

#known_resource_typesPuppet::Resource::TypeCollection

Returns The current global TypeCollection.


240
241
242
243
244
245
246
247
248
# File 'lib/puppet/node/environment.rb', line 240

def known_resource_types
  @lock.synchronize do
    if @known_resource_types.nil?
      @known_resource_types = Puppet::Resource::TypeCollection.new(self)
      @known_resource_types.import_ast(perform_initial_import(), '')
    end
    @known_resource_types
  end
end

#module(name) ⇒ Puppet::Module?

Locate a module instance by the module name alone.


268
269
270
# File 'lib/puppet/node/environment.rb', line 268

def module(name)
  modules.find {|mod| mod.name == name}
end

#module_by_forge_name(forge_name) ⇒ Puppet::Module?

Locate a module instance by the full forge name (EG authorname/module)


278
279
280
281
282
283
284
# File 'lib/puppet/node/environment.rb', line 278

def module_by_forge_name(forge_name)
  _, modname = forge_name.split('/')
  found_mod = self.module(modname)
  found_mod and found_mod.forge_name == forge_name ?
    found_mod :
    nil
end

#module_requirementsHash<String, Array<Hash<String, String>>>

All module requirements for all modules in the environment modulepath

Examples:

environment.module_requirements
# => {
#   'username/amodule' => [
#     {
#       'name'    => 'username/moduledep',
#       'version' => '1.2.3',
#       'version_requirement' => '>= 1.0.0',
#     },
#     {
#       'name'    => 'username/anotherdep',
#       'version' => '4.5.6',
#       'version_requirement' => '>= 3.0.0',
#     }
#   ]
# }
#

399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/puppet/node/environment.rb', line 399

def module_requirements
  deps = {}

  modules.each do |mod|
    next unless mod.forge_name
    deps[mod.forge_name] ||= []

    mod.dependencies and mod.dependencies.each do |mod_dep|
      dep_name = mod_dep['name'].tr('-', '/')
      (deps[dep_name] ||= []) << {
        'name'                => mod.forge_name,
        'version'             => mod.version,
        'version_requirement' => mod_dep['version_requirement']
      }
    end
  end

  deps.each do |mod, mod_deps|
    deps[mod] = mod_deps.sort_by { |d| d['name'] }
  end

  deps
end

#modulepathArray<String>

Returns All directories present on disk in the modulepath.


138
139
140
141
142
# File 'lib/puppet/node/environment.rb', line 138

def modulepath
  @modulepath.find_all do |p|
    Puppet::FileSystem.directory?(p)
  end
end

#modulesArray<Puppet::Module>

Note:

If multiple modules with the same name are present they will both be added, but methods like #module and #module_by_forge_name will return the first matching entry in this list.

Note:

This value is cached so that the filesystem doesn't have to be re-enumerated every time this method is invoked, since that enumeration could be a costly operation and this method is called frequently. The cache expiry is determined by `Puppet`.

Return all modules for this environment in the order they appear in the modulepath.


297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/puppet/node/environment.rb', line 297

def modules
  if @modules.nil?
    module_references = []
    project = Puppet.lookup(:bolt_project) { nil }
    seen_modules = if project
                     module_references << project.to_h
                     { project.name => true }
                   else
                     {}
                   end
    modulepath.each do |path|
      Dir.entries(path).each do |name|
        next unless Puppet::Module.is_module_directory?(name, path)
        warn_about_mistaken_path(path, name)
        if not seen_modules[name]
          module_references << {:name => name, :path => File.join(path, name)}
          seen_modules[name] = true
        end
      end
    end

    @modules = module_references.collect do |reference|
      begin
        Puppet::Module.new(reference[:name], reference[:path], self)
      rescue Puppet::Module::Error => e
        Puppet.log_exception(e)
        nil
      end
    end.compact
  end
  @modules
end

#modules_by_pathHash<String, Array<Puppet::Module>>

Note:

This method changes the current working directory while enumerating the modules. This seems rather dangerous.

Modules broken out by directory in the modulepath


353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# File 'lib/puppet/node/environment.rb', line 353

def modules_by_path
  modules_by_path = {}
  modulepath.each do |path|
    if Puppet::FileSystem.exist?(path)
      Dir.chdir(path) do
        module_names = Dir.entries(path).select do |name|
          Puppet::Module.is_module_directory?(name, path)
        end
        modules_by_path[path] = module_names.sort.map do |name|
          Puppet::Module.new(name, File.join(path, name), self)
        end
      end
    else
      modules_by_path[path] = []
    end
  end
  modules_by_path
end

#override_from_commandline(settings) ⇒ Puppet::Node::Environment

Creates a new Puppet::Node::Environment instance, overriding :manifest, :modulepath, or :config_version from the passed settings if they were originally set from the commandline, or returns self if there is nothing to override.


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/puppet/node/environment.rb', line 103

def override_from_commandline(settings)
  overrides = {}

  if settings.set_by_cli?(:modulepath)
    overrides[:modulepath] = self.class.split_path(settings.value(:modulepath))
  end

  if settings.set_by_cli?(:config_version)
    overrides[:config_version] = settings.value(:config_version)
  end

  if settings.set_by_cli?(:manifest)
    overrides[:manifest] = settings.value(:manifest)
  end

  overrides.empty? ?
    self :
    self.override_with(overrides)
end

#override_with(env_params) ⇒ Puppet::Node::Environment

Creates a new Puppet::Node::Environment instance, overriding any of the passed parameters.


88
89
90
91
92
93
# File 'lib/puppet/node/environment.rb', line 88

def override_with(env_params)
  return self.class.create(name,
                    env_params[:modulepath] || modulepath,
                    env_params[:manifest] || manifest,
                    env_params[:config_version] || config_version)
end

#rich_data?Boolean

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.

Checks if this environment permits use of rich data types in the catalog


220
221
222
223
224
225
226
# File 'lib/puppet/node/environment.rb', line 220

def rich_data?
  if @rich_data.nil?
    environment_conf = Puppet.lookup(:environments).get_conf(name)
    @rich_data = (environment_conf.nil? ? Puppet[:rich_data] : environment_conf.rich_data)
  end
  @rich_data
end

#static_catalogs?Boolean

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.


190
191
192
193
194
195
196
# File 'lib/puppet/node/environment.rb', line 190

def static_catalogs?
  if @static_catalogs.nil?
    environment_conf = Puppet.lookup(:environments).get_conf(name)
    @static_catalogs = (environment_conf.nil? ? Puppet[:static_catalogs] : environment_conf.static_catalogs)
  end
  @static_catalogs
end

#to_sString

Returns The stringified value of the `name` instance variable.


462
463
464
# File 'lib/puppet/node/environment.rb', line 462

def to_s
  name.to_s
end

#to_symSymbol

Note:

the `name` instance variable is a Symbol, but this casts the value to a String and then converts it back into a Symbol which will needlessly create an object that needs to be garbage collected

Returns The `name` value, cast to a string, then cast to a symbol.


478
479
480
# File 'lib/puppet/node/environment.rb', line 478

def to_sym
  to_s.to_sym
end

#to_yamlString

Return the name of the environment as a string interpretation of the object


456
457
458
# File 'lib/puppet/node/environment.rb', line 456

def to_yaml
  to_s.to_yaml
end

#validation_errorsArray<String>

Checks the environment and settings for any conflicts


209
210
211
212
213
214
215
# File 'lib/puppet/node/environment.rb', line 209

def validation_errors
  errors = []
  if conflicting_manifest_settings?
    errors << _("The 'disable_per_environment_manifest' setting is true, and the '%{env_name}' environment has an environment.conf manifest that conflicts with the 'default_manifest' setting.") % { env_name: name }
  end
  errors
end

#warn_about_mistaken_path(path, name) ⇒ 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.

Generate a warning if the given directory in a module path entry is named `lib`.


336
337
338
339
340
341
342
# File 'lib/puppet/node/environment.rb', line 336

def warn_about_mistaken_path(path, name)
  if name == "lib"
    Puppet.debug("Warning: Found directory named 'lib' in module path ('#{path}/lib'); unless " +
        "you are expecting to load a module named 'lib', your module path may be set " +
        "incorrectly.")
  end
end

#with_text_domainObject

Loads module translations for the current environment once for the lifetime of the environment. Execute a block in the context of that translation domain.


426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
# File 'lib/puppet/node/environment.rb', line 426

def with_text_domain
  return yield if Puppet[:disable_i18n]

  if @text_domain.nil?
    @text_domain = @name
    Puppet::GettextConfig.reset_text_domain(@text_domain)
    Puppet::ModuleTranslations.load_from_modulepath(modules)
  else
    Puppet::GettextConfig.use_text_domain(@text_domain)
  end

  yield
ensure
  # Is a noop if disable_i18n is true
  Puppet::GettextConfig.clear_text_domain
end