Class: Puppet::Node::Environment

Inherits:
Object
  • Object
show all
Includes:
Util::Cacher
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.

Constant Summary collapse

NO_MANIFEST =
:no_manifest

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util::Cacher

extended, included

Constructor Details

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

Note:

new is overridden to return memoized objects, so this will not be invoked with the normal Ruby initialization semantics.

Instantiate a new environment

Parameters:

  • name (Symbol)

    The environment name



116
117
118
119
120
121
122
123
124
# File 'lib/puppet/node/environment.rb', line 116

def initialize(name, modulepath, manifest, config_version)
  @name = name
  @modulepath = modulepath
  @manifest = manifest
  @config_version = config_version
  # set watching to true for legacy environments - the directory based environment loaders will set this to
  # false for directory based environments after the environment has been created.
  @watching = true
end

Instance Attribute Details

#config_versionObject (readonly)



238
239
240
# File 'lib/puppet/node/environment.rb', line 238

def config_version
  @config_version
end

#manifestObject (readonly)



232
233
234
# File 'lib/puppet/node/environment.rb', line 232

def manifest
  @manifest
end

#modulesArray<Puppet::Module> (readonly)

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.

Returns:

See Also:

  • Util::Cacher.cached_attr


330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/puppet/node/environment.rb', line 330

cached_attr(:modules, Puppet[:filetimeout]) do
  module_references = []
  seen_modules = {}
  modulepath.each do |path|
    Dir.entries(path).each do |name|
      warn_about_mistaken_path(path, name)
      next if module_references.include?(name)
      if not seen_modules[name]
        module_references << {:name => name, :path => File.join(path, name)}
        seen_modules[name] = true
      end
    end
  end

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

#nameObject (readonly)



213
214
215
# File 'lib/puppet/node/environment.rb', line 213

def name
  @name
end

Class Method Details

.clearObject

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.

Clear all memoized environments and the ‘current’ environment



205
206
207
# File 'lib/puppet/node/environment.rb', line 205

def self.clear
  seen.clear
end

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

Create a new environment with the given name

the constant Puppet::Node::Environment::NO_MANIFEST if there is none.

Parameters:

  • name (Symbol)

    the name of the

  • modulepath (Array<String>)

    the list of paths from which to load modules

  • manifest (String) (defaults to: NO_MANIFEST)

    the path to the manifest for the environment or

  • config_version (String) (defaults to: nil)

    path to a script whose output will be added to report logs (optional)

Returns:



84
85
86
87
88
89
90
91
92
# File 'lib/puppet/node/environment.rb', line 84

def self.create(name, modulepath, manifest = NO_MANIFEST, config_version = nil)
  obj = self.allocate
  obj.send(:initialize,
           name,
           expand_dirs(extralibs() + modulepath),
           manifest == NO_MANIFEST ? manifest : File.expand_path(manifest),
           config_version)
  obj
end

.currentPuppet::Node::Environment

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.

Note:

This should only used when a catalog is being compiled.

Retrieve the environment for the current process.

Returns:

  • (Puppet::Node::Environment)

    the currently set environment if one has been explicitly set, else it will return the ‘root’ environment



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

def self.current
  Puppet.deprecation_warning("Puppet::Node::Environment.current has been replaced by Puppet.lookup(:current_environment), see http://links.puppetlabs.com/current-env-deprecation")
  Puppet.lookup(:current_environment)
end

.self.new(environment) ⇒ Puppet::Node::Environment .self.new(string) ⇒ Puppet::Node::Environment .self.newPuppet::Node::Environment

Create a new environment with the given name, or return an existing one

The environment class memoizes instances so that attempts to instantiate an environment with the same name with an existing environment will return the existing environment.

Overloads:

Raises:

  • (ArgumentError)


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/puppet/node/environment.rb', line 56

def self.new(name = nil)
  return name if name.is_a?(self)
  name ||= Puppet.settings.value(:environment)

  raise ArgumentError, "Environment name must be specified" unless name

  symbol = name.to_sym

  return seen[symbol] if seen[symbol]

  obj = self.create(symbol,
           split_path(Puppet.settings.value(:modulepath, symbol)),
           Puppet.settings.value(:manifest, symbol),
           Puppet.settings.value(:config_version, symbol))
  seen[symbol] = obj
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.

Parameters:

  • name (Symbol)

    The name of the remote environment



105
106
107
# File 'lib/puppet/node/environment.rb', line 105

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

.seenObject

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.



30
31
32
# File 'lib/puppet/node/environment.rb', line 30

def self.seen
  @seen ||= {}
end

.split_path(path_string) ⇒ Object



490
491
492
# File 'lib/puppet/node/environment.rb', line 490

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

.valid_name?(name) ⇒ Boolean

Returns true if name is valid.

Parameters:

  • name (String)

    Environment name to check for valid syntax.

Returns:

  • (Boolean)

    true if name is valid



198
199
200
# File 'lib/puppet/node/environment.rb', line 198

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

Instance Method Details

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



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

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.

Parameters:

  • param (String, Symbol)

    The environment setting to look up

Returns:

  • (Object)

    The resolved setting value



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

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

#check_for_reparseObject

Checks if a reparse is required (cache of files is stale). This call does nothing unless files are being watched.



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

def check_for_reparse
  if (Puppet[:code] != @parsed_code) || (watching? && @known_resource_types && @known_resource_types.require_reparse?)
    @parsed_code = nil
    @known_resource_types = nil
  end
end

#conflicting_manifest_settings?Boolean

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.

Returns:

  • (Boolean)

    true if using directory environments, and Puppet is true, and this environment’s original environment.conf had a manifest setting that is not the Puppet.



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

def conflicting_manifest_settings?
  return false if Puppet[:environmentpath].empty? || !Puppet[:disable_per_environment_manifest]
  environment_conf = Puppet.lookup(:environments).get_conf(name)
  original_manifest = environment_conf.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.



286
287
288
289
290
291
# File 'lib/puppet/node/environment.rb', line 286

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).

Returns:

  • (Array<String>)

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



225
226
227
# File 'lib/puppet/node/environment.rb', line 225

def full_modulepath
  @modulepath
end

#hashObject



503
504
505
# File 'lib/puppet/node/environment.rb', line 503

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

#known_resource_typesPuppet::Resource::TypeCollection

Returns The current global TypeCollection.

Returns:



273
274
275
276
277
278
279
# File 'lib/puppet/node/environment.rb', line 273

def known_resource_types
  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

#module(name) ⇒ Puppet::Module?

Locate a module instance by the module name alone.

Parameters:

  • name (String)

    The module name

Returns:



299
300
301
# File 'lib/puppet/node/environment.rb', line 299

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)

Parameters:

  • forge_name (String)

    The module name

Returns:



309
310
311
312
313
314
315
# File 'lib/puppet/node/environment.rb', line 309

def module_by_forge_name(forge_name)
  author, 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',
#     }
#   ]
# }
#

Returns:



418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
# File 'lib/puppet/node/environment.rb', line 418

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.

Returns:

  • (Array<String>)

    All directories present on disk in the modulepath



217
218
219
220
221
# File 'lib/puppet/node/environment.rb', line 217

def modulepath
  @modulepath.find_all do |p|
    Puppet::FileSystem.directory?(p)
  end
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

Returns:



376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/puppet/node/environment.rb', line 376

def modules_by_path
  modules_by_path = {}
  modulepath.each do |path|
    Dir.chdir(path) do
      module_names = Dir.glob('*').select do |d|
        FileTest.directory?(d) && (File.basename(d) =~ /\A\w+(-\w+)*\Z/)
      end
      modules_by_path[path] = module_names.sort.map do |name|
        Puppet::Module.new(name, File.join(path, name), self)
      end
    end
  end
  modules_by_path
end

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

Creates a new Puppet::Node::Environment instance, overriding manfiest 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.

Parameters:

Returns:



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/puppet/node/environment.rb', line 161

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) ||
    (settings.set_by_cli?(:manifestdir) && settings.value(:manifest).start_with?(settings.value(:manifestdir)))
    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.

Parameters:

Returns:



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

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

#to_sString

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

Returns:

  • (String)

    The stringified value of the ‘name` instance variable



464
465
466
# File 'lib/puppet/node/environment.rb', line 464

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.

Returns:

  • (Symbol)

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



475
476
477
# File 'lib/puppet/node/environment.rb', line 475

def to_sym
  to_s.to_sym
end

#to_zaml(z) ⇒ Object

Return only the environment name when serializing.

The only thing we care about when serializing an environment is its identity; everything else is ephemeral and should not be stored or transmitted.



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

def to_zaml(z)
  self.to_s.to_zaml(z)
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`.

Parameters:

  • path (String)

    The module directory containing the given directory

  • name (String)

    The directory name



359
360
361
362
363
364
365
# File 'lib/puppet/node/environment.rb', line 359

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

#watch_file(file) ⇒ 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.

Set a periodic watcher on the file, so we can tell if it has changed. If watching has been turned off, this call has no effect.

Parameters:

  • file (File, String)

    File instance or filename



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

def watch_file(file)
  if watching?
    known_resource_types.watch_file(file.to_s)
  end
end

#watching=(flag) ⇒ Object

Turns watching of files on or off @ api private

Parameters:



136
137
138
# File 'lib/puppet/node/environment.rb', line 136

def watching=(flag)
  @watching = flag
end

#watching?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.

Returns if files are being watched or not.

Returns:

  • (Boolean)


129
130
131
# File 'lib/puppet/node/environment.rb', line 129

def watching?
  @watching
end