require 'puppet/parser/compiler'
# @deprecated application orchestration will be removed in puppet 7
class Puppet::Parser::EnvironmentCompiler < Puppet::Parser::Compiler
def self.compile(env, code_id=nil)
begin
env.check_for_reparse
node = Puppet::Node.new(env)
node.environment = env
new(node, :code_id => code_id).compile
rescue => detail
message = _("%{detail} in environment %{env}") % { detail: detail, env: env.name }
Puppet.log_exception(detail, message)
raise Puppet::Error, message, detail.backtrace
end
end
def initialize(node, options = {})
super(node, **options)
@overridden_functions = {}
end
def add_function_overrides
add_function_override('hiera_include', proc { Puppet.debug "Ignoring hiera_include() during environment catalog compilation" })
end
def add_function_override(func_name, override)
typed_name = Puppet::Pops::Loader::TypedName.new(:function, func_name)
loader = loaders.puppet_system_loader
# Remove and preserve existing entry. A `nil` is also preserved to indicate
# an override that didn't replace a loaded function.
entry = loader.get_entry(typed_name)
existing = entry.nil? ? nil : entry.value
loader.remove_entry(typed_name) unless existing.nil?
@overridden_functions[typed_name] = existing
# Add the override to the loader
loader.set_entry(typed_name, override)
end
def remove_function_overrides
loader = loaders.puppet_system_loader
@overridden_functions.each_pair do |typed_name, overridden|
loader.remove_entry(typed_name)
loader.set_entry(typed_name, overridden) unless overridden.nil?
end
end
def add_catalog_validators
super
add_catalog_validator(CatalogValidator::SiteValidator)
add_catalog_validator(CatalogValidator::EnvironmentRelationshipValidator)
end
def compile
Puppet.deprecation_warning("Application orchestration is deprecated. See https://puppet.com/docs/puppet/5.5/deprecated_language.html")
add_function_overrides
begin
Puppet.override(@context_overrides, _("For compiling environment catalog %{env}") % { env: environment.name }) do
@catalog.environment_instance = environment
Puppet::Util::Profiler.profile(_("Env Compile: Created settings scope"), [:compiler, :create_settings_scope]) { create_settings_scope }
Puppet::Util::Profiler.profile(_("Env Compile: Evaluated main"), [:compiler, :evaluate_main]) { evaluate_main }
Puppet::Util::Profiler.profile(_("Env Compile: Evaluated site"), [:compiler, :evaluate_site]) { evaluate_site }
Puppet::Util::Profiler.profile(_("Env Compile: Evaluated application instances"), [:compiler, :evaluate_applications]) { evaluate_applications }
Puppet::Util::Profiler.profile(_("Env Compile: Prune"), [:compiler, :prune_catalog]) { prune_catalog }
Puppet::Util::Profiler.profile(_("Env Compile: Validate Catalog pre-finish"), [:compiler, :validate_pre_finish]) do
validate_catalog(CatalogValidator::PRE_FINISH)
end
Puppet::Util::Profiler.profile(_("Env Compile: Finished catalog"), [:compiler, :finish_catalog]) { finish }
fail_on_unevaluated
Puppet::Util::Profiler.profile(_("Env Compile: Validate Catalog final"), [:compiler, :validate_final]) do
validate_catalog(CatalogValidator::FINAL)
end
if block_given?
yield @catalog
else
@catalog
end
end
ensure
remove_function_overrides
end
end
# @api private
def prune_catalog
prune_env_catalog
end
# Prunes the catalog by dropping all resources that are not contained under the Site (if a site expression is used).
# As a consequence all edges to/from dropped resources are also dropped.
# Once the pruning is performed, this compiler returns the pruned list when calling the #resources method.
# The pruning does not alter the order of resources in the resources list.
#
def prune_env_catalog
# Everything under Class[main], that is not under (inclusive of) Site[site] should be pruned as those resources
# are intended for nodes in a node catalog.
#
the_main_class_resource = @catalog.resource('Class', '')
the_site_resource = @catalog.resource('Site', 'site')
# Get downstream vertexes returns a hash where the keys are the resources and values nesting level
rooted_in_main = @catalog.downstream_from_vertex(the_main_class_resource).keys
to_be_removed =
if the_site_resource
keep_from_site = @catalog.downstream_from_vertex(the_site_resource).keys
keep_from_site << the_site_resource
rooted_in_main - keep_from_site
else
rooted_in_main
end
@catalog.remove_resource(*to_be_removed)
# The compiler keeps a list of added resources, this shadows that list with the now pruned result
@pruned_resources = @catalog.resources
end
def add_resource(scope, resource)
@resources << resource
@catalog.add_resource(resource)
if !resource.class? && resource[:stage]
raise ArgumentError, _("Only classes can set 'stage'; normal resources like %{resource} cannot change run stage") % { resource: resource }
end
# Stages should not be inside of classes. They are always a
# top-level container, regardless of where they appear in the
# manifest.
return if resource.stage?
# This adds a resource to the class it lexically appears in in the
# manifest.
unless resource.class?
@catalog.add_edge(scope.resource, resource)
end
resource.mark_unevaluated_consumer if is_capability_consumer?(resource)
assert_app_in_site(scope, resource)
end
def evaluate_ast_node()
# Do nothing, the environment catalog is not built for a particular node.
end
def on_empty_site
Puppet.warning(_("Environment Compiler: Could not find a site definition to evaluate"))
end
def evaluate_applications
exceptwrap do
resources.select { |resource| type = resource.resource_type; type.is_a?(Puppet::Resource::Type) && type.application? }.each do |resource|
Puppet::Util::Profiler.profile(_("Evaluated application %{resource}") % { resource: resource }, [:compiler, :evaluate_resource, resource]) do
resource.evaluate
end
end
end
end
def evaluate_classes(titles, scope, lazy)
# Always lazy in an Environment compilation
super(titles, scope, true)
end
# Overrides the regular compiler to be able to return the list of resources after a prune
# has taken place in the graph representation. Before a prune, the list is the same as in the regular
# compiler
#
def resources
@pruned_resources || super
end
def is_capability?(value)
if value.is_a?(Array)
value.find { |ev| is_capability?(ev) }
elsif value.is_a?(Puppet::Resource)
rstype = value.resource_type
rstype.nil? ? false : rstype.is_capability?
else
false
end
end
private :is_capability?
def is_capability_consumer?(resource)
resource.eachparam { |param| return true if (param.name == :consume || param.name == :require) && is_capability?(param.value) }
false
end
private :is_capability_consumer?
end
Copyright 2K16 - 2K18 Indonesian Hacker Rulez