puppet 4.4.2 → 4.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- data/CONTRIBUTING.md +5 -5
- data/Gemfile +2 -2
- data/LICENSE +2 -2
- data/README.md +5 -0
- data/ext/project_data.yaml +2 -0
- data/lib/hiera_puppet.rb +6 -14
- data/lib/puppet/application/agent.rb +2 -3
- data/lib/puppet/data_providers/hiera_config.rb +2 -4
- data/lib/puppet/data_providers/hiera_interpolate.rb +12 -154
- data/lib/puppet/data_providers/json_data_provider_factory.rb +0 -7
- data/lib/puppet/data_providers/yaml_data_provider_factory.rb +2 -8
- data/lib/puppet/defaults.rb +70 -7
- data/lib/puppet/functions.rb +69 -0
- data/lib/puppet/functions/dig.rb +39 -0
- data/lib/puppet/functions/lest.rb +53 -0
- data/lib/puppet/functions/lookup.rb +40 -27
- data/lib/puppet/functions/new.rb +502 -0
- data/lib/puppet/functions/regsubst.rb +11 -10
- data/lib/puppet/functions/then.rb +74 -0
- data/lib/puppet/functions/type.rb +4 -4
- data/lib/puppet/functions/with.rb +1 -1
- data/lib/puppet/indirector/catalog/compiler.rb +2 -0
- data/lib/puppet/indirector/resource_type/parser.rb +5 -0
- data/lib/puppet/indirector/rest.rb +5 -1
- data/lib/puppet/loaders.rb +2 -0
- data/lib/puppet/metatype/manager.rb +19 -2
- data/lib/puppet/module_tool/applications/application.rb +1 -1
- data/lib/puppet/module_tool/skeleton/templates/generator/Gemfile +6 -2
- data/lib/puppet/module_tool/skeleton/templates/generator/Rakefile +19 -4
- data/lib/puppet/module_tool/skeleton/templates/generator/{tests → examples}/init.pp.erb +1 -1
- data/lib/puppet/module_tool/skeleton/templates/generator/spec/classes/init_spec.rb.erb +0 -1
- data/lib/puppet/network/http/api/master/v3/environment.rb +6 -2
- data/lib/puppet/parser/ast/pops_bridge.rb +20 -3
- data/lib/puppet/parser/compiler/catalog_validator/relationship_validator.rb +24 -2
- data/lib/puppet/parser/e4_parser_adapter.rb +13 -12
- data/lib/puppet/parser/environment_compiler.rb +2 -2
- data/lib/puppet/parser/resource.rb +14 -5
- data/lib/puppet/parser/scope.rb +18 -15
- data/lib/puppet/plugins/data_providers/data_provider.rb +19 -8
- data/lib/puppet/pops.rb +6 -0
- data/lib/puppet/pops/adapters.rb +5 -1
- data/lib/puppet/pops/evaluator/access_operator.rb +52 -14
- data/lib/puppet/pops/evaluator/compare_operator.rb +34 -4
- data/lib/puppet/pops/evaluator/evaluator_impl.rb +75 -22
- data/lib/puppet/pops/evaluator/literal_evaluator.rb +7 -6
- data/lib/puppet/pops/evaluator/runtime3_converter.rb +13 -1
- data/lib/puppet/pops/evaluator/runtime3_support.rb +14 -4
- data/lib/puppet/pops/functions/dispatcher.rb +1 -1
- data/lib/puppet/pops/issues.rb +18 -2
- data/lib/puppet/pops/loader/base_loader.rb +48 -7
- data/lib/puppet/pops/loader/dependency_loader.rb +27 -2
- data/lib/puppet/pops/loader/loader.rb +12 -0
- data/lib/puppet/pops/loader/predefined_loader.rb +29 -0
- data/lib/puppet/pops/loader/runtime3_type_loader.rb +57 -0
- data/lib/puppet/pops/loader/static_loader.rb +92 -5
- data/lib/puppet/pops/loader/type_definition_instantiator.rb +25 -3
- data/lib/puppet/pops/loaders.rb +84 -14
- data/lib/puppet/pops/lookup/explainer.rb +38 -1
- data/lib/puppet/pops/lookup/interpolation.rb +115 -0
- data/lib/puppet/pops/lookup/sub_lookup.rb +86 -0
- data/lib/puppet/pops/model/ast_transformer.rb +8 -1
- data/lib/puppet/pops/model/factory.rb +31 -8
- data/lib/puppet/pops/model/model.rb +8 -0
- data/lib/puppet/pops/model/model_label_provider.rb +1 -0
- data/lib/puppet/pops/model/model_meta.rb +7 -1
- data/lib/puppet/pops/model/model_tree_dumper.rb +4 -0
- data/lib/puppet/pops/parser/egrammar.ra +24 -7
- data/lib/puppet/pops/parser/eparser.rb +863 -798
- data/lib/puppet/pops/parser/evaluating_parser.rb +4 -0
- data/lib/puppet/pops/parser/locator.rb +8 -4
- data/lib/puppet/pops/pcore.rb +30 -0
- data/lib/puppet/pops/types/class_loader.rb +2 -4
- data/lib/puppet/pops/types/implementation_registry.rb +146 -0
- data/lib/puppet/pops/types/iterable.rb +4 -4
- data/lib/puppet/pops/types/p_object_type.rb +846 -0
- data/lib/puppet/pops/types/p_runtime_type.rb +102 -0
- data/lib/puppet/pops/types/p_sem_ver_range_type.rb +164 -0
- data/lib/puppet/pops/types/p_sem_ver_type.rb +113 -0
- data/lib/puppet/pops/types/puppet_object.rb +21 -0
- data/lib/puppet/pops/types/ruby_generator.rb +258 -0
- data/lib/puppet/pops/types/string_converter.rb +922 -0
- data/lib/puppet/pops/types/type_calculator.rb +29 -5
- data/lib/puppet/pops/types/type_conversion_error.rb +15 -0
- data/lib/puppet/pops/types/type_factory.rb +49 -16
- data/lib/puppet/pops/types/type_formatter.rb +335 -112
- data/lib/puppet/pops/types/type_mismatch_describer.rb +110 -29
- data/lib/puppet/pops/types/type_parser.rb +205 -197
- data/lib/puppet/pops/types/types.rb +481 -103
- data/lib/puppet/pops/validation.rb +1 -1
- data/lib/puppet/pops/validation/checker4_0.rb +66 -4
- data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
- data/lib/puppet/pops/visitor.rb +3 -1
- data/lib/puppet/property.rb +1 -1
- data/lib/puppet/provider/augeas/augeas.rb +1 -1
- data/lib/puppet/provider/package/pip.rb +64 -20
- data/lib/puppet/provider/package/rpm.rb +112 -0
- data/lib/puppet/provider/package/yum.rb +7 -68
- data/lib/puppet/provider/service/daemontools.rb +3 -3
- data/lib/puppet/provider/service/init.rb +4 -2
- data/lib/puppet/provider/service/runit.rb +3 -3
- data/lib/puppet/provider/service/smf.rb +6 -3
- data/lib/puppet/provider/service/systemd.rb +59 -73
- data/lib/puppet/reference/providers.rb +1 -2
- data/lib/puppet/resource.rb +54 -37
- data/lib/puppet/resource/catalog.rb +31 -29
- data/lib/puppet/resource/type_collection.rb +23 -8
- data/lib/puppet/settings.rb +4 -2
- data/lib/puppet/settings/base_setting.rb +9 -3
- data/lib/puppet/settings/symbolic_enum_setting.rb +17 -0
- data/lib/puppet/test/test_helper.rb +0 -1
- data/lib/puppet/type.rb +9 -3
- data/lib/puppet/type/exec.rb +17 -17
- data/lib/puppet/type/file.rb +12 -0
- data/lib/puppet/type/file/content.rb +6 -6
- data/lib/puppet/type/file/ensure.rb +4 -4
- data/lib/puppet/type/file/source.rb +4 -4
- data/lib/puppet/type/file/target.rb +2 -2
- data/lib/puppet/type/mount.rb +18 -1
- data/lib/puppet/type/package.rb +3 -3
- data/lib/puppet/type/schedule.rb +4 -4
- data/lib/puppet/type/service.rb +15 -0
- data/lib/puppet/type/sshkey.rb +5 -3
- data/lib/puppet/type/tidy.rb +3 -3
- data/lib/puppet/type/zone.rb +5 -5
- data/lib/puppet/util/feature.rb +1 -1
- data/lib/puppet/util/monkey_patches.rb +8 -0
- data/lib/puppet/util/network_device/cisco/device.rb +16 -6
- data/lib/puppet/util/network_device/cisco/interface.rb +5 -6
- data/lib/puppet/util/plist.rb +3 -3
- data/lib/puppet/version.rb +1 -1
- data/spec/fixtures/unit/application/environments/production/data/common.yaml +13 -0
- data/spec/fixtures/unit/data_providers/environments/production/modules/abc/lib/puppet/functions/abc/data.rb +2 -1
- data/spec/fixtures/unit/data_providers/environments/production/modules/abc/manifests/init.pp +2 -1
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/data/empty_key.json +1 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/hiera.yaml +5 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/manifests/init.pp +2 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_json/metadata.json +9 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/data/empty_key.yaml +1 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/hiera.yaml +5 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/manifests/init.pp +2 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_key_yaml/metadata.json +9 -0
- data/spec/fixtures/unit/functions/lookup/environments/production/modules/empty_yaml/data/empty.yaml +1 -0
- data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/usee/lib/puppet/type/usee_type.rb +5 -0
- data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/manifests/init.pp +6 -0
- data/spec/fixtures/unit/provider/service/smf/svcs.out +4 -3
- data/spec/integration/module_tool/tar/mini_spec.rb +27 -27
- data/spec/integration/parser/catalog_spec.rb +14 -2
- data/spec/integration/parser/compiler_spec.rb +94 -3
- data/spec/integration/parser/resource_expressions_spec.rb +1 -1
- data/spec/integration/resource/type_collection_spec.rb +8 -0
- data/spec/lib/puppet_spec/compiler.rb +11 -4
- data/spec/shared_contexts/types_setup.rb +4 -0
- data/spec/unit/application/lookup_spec.rb +91 -9
- data/spec/unit/appmgmt_spec.rb +44 -35
- data/spec/unit/capability_spec.rb +33 -53
- data/spec/unit/data_providers/function_data_provider_spec.rb +19 -1
- data/spec/unit/data_providers/hiera_data_provider_spec.rb +1 -1
- data/spec/unit/defaults_spec.rb +18 -0
- data/spec/unit/functions/assert_type_spec.rb +1 -1
- data/spec/unit/functions/dig_spec.rb +58 -0
- data/spec/unit/functions/lest_spec.rb +34 -0
- data/spec/unit/functions/lookup_spec.rb +108 -2
- data/spec/unit/functions/new_spec.rb +543 -0
- data/spec/unit/functions/regsubst_spec.rb +8 -0
- data/spec/unit/functions/then_spec.rb +40 -0
- data/spec/unit/functions4_spec.rb +78 -10
- data/spec/unit/hiera_puppet_spec.rb +49 -8
- data/spec/unit/indirector/resource_type/parser_spec.rb +5 -0
- data/spec/unit/indirector/rest_spec.rb +12 -0
- data/spec/unit/network/http/api/master/v3/environment_spec.rb +60 -0
- data/spec/unit/node/environment_spec.rb +10 -0
- data/spec/unit/parser/compiler_spec.rb +20 -1
- data/spec/unit/parser/functions/create_resources_spec.rb +2 -2
- data/spec/unit/parser/functions/shared.rb +1 -1
- data/spec/unit/parser/resource_spec.rb +8 -1
- data/spec/unit/parser/scope_spec.rb +45 -0
- data/spec/unit/pops/evaluator/access_ops_spec.rb +14 -0
- data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +13 -5
- data/spec/unit/pops/loaders/static_loader_spec.rb +92 -1
- data/spec/unit/{data_providers/hiera_interpolation_spec.rb → pops/lookup/interpolation_spec.rb} +7 -5
- data/spec/unit/pops/parser/lexer2_spec.rb +2 -9
- data/spec/unit/pops/parser/parse_application_spec.rb +3 -8
- data/spec/unit/pops/parser/parse_basic_expressions_spec.rb +19 -0
- data/spec/unit/pops/parser/parse_capabilities_spec.rb +3 -10
- data/spec/unit/pops/parser/parse_site_spec.rb +19 -10
- data/spec/unit/pops/parser/parser_rspec_helper.rb +0 -4
- data/spec/unit/pops/types/enumeration_spec.rb +13 -12
- data/spec/unit/pops/types/iterable_spec.rb +2 -2
- data/spec/unit/pops/types/p_object_type_spec.rb +1060 -0
- data/spec/unit/pops/types/p_sem_ver_type_spec.rb +285 -0
- data/spec/unit/pops/types/recursion_guard_spec.rb +19 -17
- data/spec/unit/pops/types/ruby_generator_spec.rb +261 -0
- data/spec/unit/pops/types/string_converter_spec.rb +904 -0
- data/spec/unit/pops/types/type_calculator_spec.rb +430 -406
- data/spec/unit/pops/types/type_factory_spec.rb +119 -104
- data/spec/unit/pops/types/type_formatter_spec.rb +73 -6
- data/spec/unit/pops/types/type_mismatch_describer_spec.rb +2 -2
- data/spec/unit/pops/types/type_parser_spec.rb +54 -15
- data/spec/unit/pops/types/types_spec.rb +113 -8
- data/spec/unit/pops/validator/validator_spec.rb +84 -10
- data/spec/unit/provider/package/pip3_spec.rb +9 -270
- data/spec/unit/provider/package/pip_spec.rb +85 -30
- data/spec/unit/provider/package/rpm_spec.rb +160 -3
- data/spec/unit/provider/package/yum_spec.rb +23 -134
- data/spec/unit/provider/service/smf_spec.rb +14 -2
- data/spec/unit/provider/service/systemd_spec.rb +33 -41
- data/spec/unit/resource/capability_finder_spec.rb +10 -2
- data/spec/unit/settings/file_setting_spec.rb +6 -0
- data/spec/unit/transaction/additional_resource_generator_spec.rb +80 -65
- data/spec/unit/type/mount_spec.rb +51 -10
- data/spec/unit/type/service_spec.rb +16 -0
- data/spec/unit/type_spec.rb +14 -0
- data/spec/unit/util/feature_spec.rb +1 -1
- data/spec/unit/util/monkey_patches_spec.rb +60 -0
- data/spec/unit/util/network_device/cisco/device_spec.rb +1 -1
- metadata +63 -11
- data/lib/puppet/pops/types/types_meta.rb +0 -0
- data/spec/integration/provider/package_spec.rb +0 -35
@@ -42,14 +42,36 @@ class TypeDefinitionInstantiator
|
|
42
42
|
# the loader is known - hence this mechanism
|
43
43
|
private_loader = loader.private_loader
|
44
44
|
Adapters::LoaderAdapter.adapt(type_definition).loader = private_loader
|
45
|
-
|
46
|
-
Types::PTypeAliasType.new(name, type_definition.type_expr)
|
45
|
+
create_type(type_definition, loader)
|
47
46
|
end
|
48
47
|
|
49
48
|
def self.create_from_model(type_definition, loader)
|
49
|
+
typed_name = Loader::TypedName.new(:type, type_definition.name.downcase)
|
50
|
+
type = create_type(type_definition, loader)
|
51
|
+
loader.set_entry(
|
52
|
+
typed_name,
|
53
|
+
type,
|
54
|
+
Adapters::SourcePosAdapter.adapt(type_definition).to_uri)
|
55
|
+
type
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.create_type(type_definition, loader)
|
59
|
+
type_expr = type_definition.type_expr
|
50
60
|
name = type_definition.name
|
51
|
-
|
61
|
+
if object_definition?(type_expr)
|
62
|
+
# No need for an alias. The Object type itself will receive the name instead
|
63
|
+
i12n_hash_expr = type_expr.keys.empty? ? nil : type_expr.keys[0]
|
64
|
+
Types::PObjectType.new(name, i12n_hash_expr)
|
65
|
+
else
|
66
|
+
Types::PTypeAliasType.new(name, type_expr)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
private_class_method :create_type
|
70
|
+
|
71
|
+
def self.object_definition?(te)
|
72
|
+
te.is_a?(Model::AccessExpression) && (left = te.left_expr).is_a?(Model::QualifiedReference) && left.cased_value == 'Object'
|
52
73
|
end
|
74
|
+
private_class_method :object_definition?
|
53
75
|
end
|
54
76
|
end
|
55
77
|
end
|
data/lib/puppet/pops/loaders.rb
CHANGED
@@ -6,10 +6,9 @@ class Loaders
|
|
6
6
|
attr_reader :puppet_system_loader
|
7
7
|
attr_reader :public_environment_loader
|
8
8
|
attr_reader :private_environment_loader
|
9
|
+
attr_reader :implementation_registry
|
9
10
|
|
10
11
|
def initialize(environment)
|
11
|
-
# The static loader can only be changed after a reboot
|
12
|
-
@@static_loader ||= Loader::StaticLoader.new()
|
13
12
|
|
14
13
|
# Create the set of loaders
|
15
14
|
# 1. Puppet, loads from the "running" puppet - i.e. bundled functions, types, extension points and extensions
|
@@ -26,28 +25,81 @@ class Loaders
|
|
26
25
|
#
|
27
26
|
@private_environment_loader = create_environment_loader(environment)
|
28
27
|
|
29
|
-
# 3.
|
28
|
+
# 3. The implementation registry maintains mappings between Puppet types and Runtime types for
|
29
|
+
# the current environment
|
30
|
+
@implementation_registry = Types::ImplementationRegistry.new(@private_environment_loader)
|
31
|
+
Pcore.init(@puppet_system_loader, @implementation_registry)
|
32
|
+
|
33
|
+
# 4. module loaders are set up from the create_environment_loader, they register themselves
|
30
34
|
end
|
31
35
|
|
32
36
|
# Clears the cached static and puppet_system loaders (to enable testing)
|
33
37
|
#
|
34
38
|
def self.clear
|
35
39
|
@@static_loader = nil
|
36
|
-
@puppet_system_loader = nil
|
37
40
|
end
|
38
41
|
|
39
|
-
#
|
40
|
-
#
|
41
|
-
# is `nil` or empty.
|
42
|
+
# Calls {#loaders} to obtain the {{Loaders}} instance and then uses it to find the appropriate loader
|
43
|
+
# for the given `module_name`, or for the environment in case `module_name` is `nil` or empty.
|
42
44
|
#
|
43
45
|
# @param module_name [String,nil] the name of the module
|
44
46
|
# @return [Loader::Loader] the found loader
|
45
47
|
# @raise [Puppet::ParseError] if no loader can be found
|
46
48
|
# @api private
|
47
49
|
def self.find_loader(module_name)
|
50
|
+
loaders.find_loader(module_name)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.static_loader
|
54
|
+
# The static loader can only be changed after a reboot
|
55
|
+
@@static_loader ||= Loader::StaticLoader.new()
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.implementation_registry
|
59
|
+
loaders = Puppet.lookup(:loaders) { nil }
|
60
|
+
loaders.nil? ? nil : loaders.implementation_registry
|
61
|
+
end
|
62
|
+
|
63
|
+
def register_implementations(*obj_classes)
|
64
|
+
loader = @private_environment_loader
|
65
|
+
types = obj_classes.map do |obj_class|
|
66
|
+
type = obj_class._ptype
|
67
|
+
typed_name = Loader::Loader::TypedName.new(:type, type.name.downcase)
|
68
|
+
entry = loader.loaded_entry(typed_name)
|
69
|
+
loader.set_entry(typed_name, type, obj_class._plocation) if entry.nil? || entry.value.nil?
|
70
|
+
type
|
71
|
+
end
|
72
|
+
# Resolve lazy so that all types can cross reference eachother
|
73
|
+
parser = Types::TypeParser.new
|
74
|
+
types.each { |type| type.resolve(parser, loader) }
|
75
|
+
end
|
76
|
+
|
77
|
+
# Register the given type with the Runtime3TypeLoader. The registration will not happen unless
|
78
|
+
# the type system has been initialized.
|
79
|
+
#
|
80
|
+
# @param name [String,Symbol] the name of the entity being set
|
81
|
+
# @param origin [URI] the origin or the source where the type is defined
|
82
|
+
# @api private
|
83
|
+
def self.register_runtime3_type(name, origin)
|
84
|
+
loaders = Puppet.lookup(:loaders) { nil }
|
85
|
+
unless loaders.nil?
|
86
|
+
name = name.to_s
|
87
|
+
caps_name = Types::TypeFormatter.singleton.capitalize_segments(name)
|
88
|
+
typed_name = Loader::Loader::TypedName.new(:type, name.downcase)
|
89
|
+
loaders.runtime3_type_loader.set_entry(typed_name, Types::PResourceType.new(caps_name), origin)
|
90
|
+
end
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
|
94
|
+
# Finds the `Loaders` instance by looking up the :loaders in the global Puppet context
|
95
|
+
#
|
96
|
+
# @return [Loaders] the loaders instance
|
97
|
+
# @raise [Puppet::ParseError] if loader has been bound to the global context
|
98
|
+
# @api private
|
99
|
+
def self.loaders
|
48
100
|
loaders = Puppet.lookup(:loaders) { nil }
|
49
101
|
raise Puppet::ParseError, "Internal Error: Puppet Context ':loaders' missing" if loaders.nil?
|
50
|
-
loaders
|
102
|
+
loaders
|
51
103
|
end
|
52
104
|
|
53
105
|
# Finds the appropriate loader for the given `module_name`, or for the environment in case `module_name`
|
@@ -77,13 +129,17 @@ class Loaders
|
|
77
129
|
end
|
78
130
|
|
79
131
|
def static_loader
|
80
|
-
|
132
|
+
self.class.static_loader
|
81
133
|
end
|
82
134
|
|
83
135
|
def puppet_system_loader
|
84
136
|
@puppet_system_loader
|
85
137
|
end
|
86
138
|
|
139
|
+
def runtime3_type_loader
|
140
|
+
@runtime3_type_loader
|
141
|
+
end
|
142
|
+
|
87
143
|
def public_loader_for_module(module_name)
|
88
144
|
md = @module_resolver[module_name] || (return nil)
|
89
145
|
# Note, this loader is not resolved until there is interest in the visibility of entities from the
|
@@ -130,12 +186,16 @@ class Loaders
|
|
130
186
|
module_name = nil
|
131
187
|
loader_name = "environment:#{environment.name}"
|
132
188
|
env_conf = Puppet.lookup(:environments).get_conf(environment.name)
|
189
|
+
|
190
|
+
# Create the 3.x resource type loader
|
191
|
+
@runtime3_type_loader = Loader::Runtime3TypeLoader.new(puppet_system_loader, environment)
|
192
|
+
|
133
193
|
if env_conf.nil? || !env_conf.is_a?(Puppet::Settings::EnvironmentConf)
|
134
194
|
# Not a real directory environment, cannot work as a module TODO: Drop when legacy env are dropped?
|
135
|
-
loader = Loader::SimpleEnvironmentLoader.new(
|
195
|
+
loader = Loader::SimpleEnvironmentLoader.new(@runtime3_type_loader, loader_name)
|
136
196
|
else
|
137
197
|
# View the environment as a module to allow loading from it - this module is always called 'environment'
|
138
|
-
loader = Loader::ModuleLoaders.module_loader_from(
|
198
|
+
loader = Loader::ModuleLoaders.module_loader_from(@runtime3_type_loader, self, 'environment', env_conf.path_to_env)
|
139
199
|
end
|
140
200
|
|
141
201
|
# An environment has a module path even if it has a null loader
|
@@ -270,9 +330,19 @@ class Loaders
|
|
270
330
|
|
271
331
|
def create_loader_with_only_dependencies_visible(from_module_data)
|
272
332
|
if from_module_data.unmet_dependencies?
|
273
|
-
Puppet
|
274
|
-
|
275
|
-
|
333
|
+
if Puppet[:strict] != :off
|
334
|
+
msg = "ModuleLoader: module '#{from_module_data.name}' has unresolved dependencies" \
|
335
|
+
" - it will only see those that are resolved." \
|
336
|
+
" Use 'puppet module list --tree' to see information about modules"
|
337
|
+
case Puppet[:strict]
|
338
|
+
when :error
|
339
|
+
raise LoaderError.new(msg)
|
340
|
+
when :warning
|
341
|
+
Puppet.warn_once(:unresolved_module_dependencies,
|
342
|
+
"unresolved_dependencies_for_module_#{from_module_data.name}",
|
343
|
+
msg)
|
344
|
+
end
|
345
|
+
end
|
276
346
|
end
|
277
347
|
dependency_loaders = from_module_data.dependency_names.collect { |name| @index[name].public_loader }
|
278
348
|
Loader::DependencyLoader.new(from_module_data.public_loader, from_module_data.name, dependency_loaders)
|
@@ -367,13 +367,46 @@ module Puppet::Pops::Lookup
|
|
367
367
|
end
|
368
368
|
end
|
369
369
|
|
370
|
+
class ExplainSubLookup < ExplainTreeNode
|
371
|
+
def initialize(parent, sub_key)
|
372
|
+
super(parent)
|
373
|
+
@sub_key = sub_key
|
374
|
+
end
|
375
|
+
|
376
|
+
def dump_on(io, indent, first_indent)
|
377
|
+
io << indent << 'Sub key: "' << @sub_key.join('.') << "\"\n"
|
378
|
+
indent = increase_indent(indent)
|
379
|
+
branches.each {|b| b.dump_on(io, indent, indent)}
|
380
|
+
dump_outcome(io, indent)
|
381
|
+
end
|
382
|
+
|
383
|
+
def type
|
384
|
+
:sub_key
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
class ExplainKeySegment < ExplainTreeNode
|
389
|
+
def initialize(parent, segment)
|
390
|
+
super(parent)
|
391
|
+
@segment = segment
|
392
|
+
end
|
393
|
+
|
394
|
+
def dump_on(io, indent, first_indent)
|
395
|
+
dump_outcome(io, indent)
|
396
|
+
end
|
397
|
+
|
398
|
+
def type
|
399
|
+
:segment
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
370
403
|
class ExplainScope < ExplainTreeNode
|
371
404
|
def initialize(parent)
|
372
405
|
super(parent)
|
373
406
|
end
|
374
407
|
|
375
408
|
def dump_on(io, indent, first_indent)
|
376
|
-
io << indent << 'Global Scope' << "\
|
409
|
+
io << indent << 'Global Scope' << "\n"
|
377
410
|
indent = increase_indent(indent)
|
378
411
|
dump_outcome(io, indent)
|
379
412
|
end
|
@@ -406,6 +439,10 @@ module Puppet::Pops::Lookup
|
|
406
439
|
ExplainMerge.new(@current, qualifier)
|
407
440
|
when :scope
|
408
441
|
ExplainScope.new(@current)
|
442
|
+
when :sub_lookup
|
443
|
+
ExplainSubLookup.new(@current, qualifier)
|
444
|
+
when :segment
|
445
|
+
ExplainKeySegment.new(@current, qualifier)
|
409
446
|
when :meta, :data
|
410
447
|
ExplainTop.new(@current, qualifier_type, qualifier)
|
411
448
|
when :invalid_key
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require_relative 'sub_lookup'
|
2
|
+
|
3
|
+
# Add support for Hiera-like interpolation expressions. The expressions may contain keys that uses dot-notation
|
4
|
+
# to further navigate into hashes and arrays
|
5
|
+
#
|
6
|
+
module Puppet::Pops
|
7
|
+
module Lookup
|
8
|
+
module Interpolation
|
9
|
+
include SubLookup
|
10
|
+
|
11
|
+
def interpolate(subject, lookup_invocation, allow_methods)
|
12
|
+
case subject
|
13
|
+
when String
|
14
|
+
subject.index('%{').nil? ? subject : interpolate_string(subject, lookup_invocation, allow_methods)
|
15
|
+
when Array
|
16
|
+
subject.map { |element| interpolate(element, lookup_invocation, allow_methods) }
|
17
|
+
when Hash
|
18
|
+
Hash[subject.map { |k, v| [k, interpolate(v, lookup_invocation, allow_methods)] }]
|
19
|
+
else
|
20
|
+
subject
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
EMPTY_INTERPOLATIONS = {
|
27
|
+
'' => true,
|
28
|
+
'::' => true,
|
29
|
+
'""' => true,
|
30
|
+
"''" => true,
|
31
|
+
'"::"' => true,
|
32
|
+
"'::'" => true
|
33
|
+
}.freeze
|
34
|
+
|
35
|
+
# Matches a key that is quoted using a matching pair of either single or double quotes.
|
36
|
+
QUOTED_KEY = /^(?:"([^"]+)"|'([^']+)')$/
|
37
|
+
|
38
|
+
def interpolate_string(subject, lookup_invocation, allow_methods)
|
39
|
+
lookup_invocation.with(:interpolate, subject) do
|
40
|
+
subject.gsub(/%\{([^\}]*)\}/) do |match|
|
41
|
+
expr = $1
|
42
|
+
# Leading and trailing spaces inside an interpolation expression are insignificant
|
43
|
+
expr.strip!
|
44
|
+
value = nil
|
45
|
+
unless EMPTY_INTERPOLATIONS[expr]
|
46
|
+
method_key, key = get_method_and_data(expr, allow_methods)
|
47
|
+
is_alias = method_key == 'alias'
|
48
|
+
|
49
|
+
# Alias is only permitted if the entire string is equal to the interpolate expression
|
50
|
+
raise Puppet::DataBinding::LookupError, "'alias' interpolation is only permitted if the expression is equal to the entire string" if is_alias && subject != match
|
51
|
+
|
52
|
+
segments = split_key(key) { |problem| Puppet::DataBinding::LookupError.new("#{problem} in string: #{subject}") }
|
53
|
+
root_key = segments.shift
|
54
|
+
value = interpolate_method(method_key).call(root_key, lookup_invocation)
|
55
|
+
value = sub_lookup(key, lookup_invocation, segments, value) unless segments.empty?
|
56
|
+
value = lookup_invocation.check(key) { interpolate(value, lookup_invocation, allow_methods) }
|
57
|
+
|
58
|
+
# break gsub and return value immediately if this was an alias substitution. The value might be something other than a String
|
59
|
+
return value if is_alias
|
60
|
+
end
|
61
|
+
value || ''
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def interpolate_method(method_key)
|
67
|
+
@@interpolate_methods ||= begin
|
68
|
+
global_lookup = lambda { |key, lookup_invocation| Lookup.lookup(key, nil, '', true, nil, lookup_invocation) }
|
69
|
+
scope_lookup = lambda do |key, lookup_invocation|
|
70
|
+
lookup_invocation.with(:scope, nil) do
|
71
|
+
ovr = lookup_invocation.override_values
|
72
|
+
if ovr.include?(key)
|
73
|
+
lookup_invocation.report_found_in_overrides(key, ovr[key])
|
74
|
+
else
|
75
|
+
scope = lookup_invocation.scope
|
76
|
+
if scope.include?(key)
|
77
|
+
lookup_invocation.report_found(key, scope[key])
|
78
|
+
else
|
79
|
+
defaults = lookup_invocation.default_values
|
80
|
+
if defaults.include?(key)
|
81
|
+
lookup_invocation.report_found_in_defaults(key, defaults[key])
|
82
|
+
else
|
83
|
+
nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
{
|
91
|
+
'lookup' => global_lookup,
|
92
|
+
'hiera' => global_lookup, # this is just an alias for 'lookup'
|
93
|
+
'alias' => global_lookup, # same as 'lookup' but expression must be entire string and result is not subject to string substitution
|
94
|
+
'scope' => scope_lookup,
|
95
|
+
'literal' => lambda { |key, _| key }
|
96
|
+
}.freeze
|
97
|
+
end
|
98
|
+
interpolate_method = @@interpolate_methods[method_key]
|
99
|
+
raise Puppet::DataBinding::LookupError, "Unknown interpolation method '#{method_key}'" unless interpolate_method
|
100
|
+
interpolate_method
|
101
|
+
end
|
102
|
+
|
103
|
+
def get_method_and_data(data, allow_methods)
|
104
|
+
if match = data.match(/^(\w+)\((?:["]([^"]+)["]|[']([^']+)['])\)$/)
|
105
|
+
raise Puppet::DataBinding::LookupError, 'Interpolation using method syntax is not allowed in this context' unless allow_methods
|
106
|
+
key = match[1]
|
107
|
+
data = match[2] || match[3] # double or single qouted
|
108
|
+
else
|
109
|
+
key = 'scope'
|
110
|
+
end
|
111
|
+
[key, data]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Puppet::Pops
|
2
|
+
module Lookup
|
3
|
+
module SubLookup
|
4
|
+
# Split key into segments. A segment may be a quoted string (both single and double quotes can
|
5
|
+
# be used) and the segment separator is the '.' character. Whitespace will be trimmed off on
|
6
|
+
# both sides of each segment. Whitespace within quotes are not trimmed.
|
7
|
+
#
|
8
|
+
# If the key cannot be parsed, this method will yield a string describing the problem to a one
|
9
|
+
# parameter block. The block must return an exception instance.
|
10
|
+
#
|
11
|
+
# @param key [String] the string to split
|
12
|
+
# @return Array<String> the array of segments
|
13
|
+
# @yieldparam problem [String] the problem, i.e. 'Syntax error'
|
14
|
+
# @yieldreturn [Exception] the exception to raise
|
15
|
+
#
|
16
|
+
# @api public
|
17
|
+
def split_key(key)
|
18
|
+
segments = key.split(/(\s*"[^"]+"\s*|\s*'[^']+'\s*|[^'".]+)/)
|
19
|
+
if segments.empty?
|
20
|
+
# Only happens if the original key was an empty string
|
21
|
+
''
|
22
|
+
elsif segments.shift == ''
|
23
|
+
count = segments.size
|
24
|
+
raise yield('Syntax error') unless count > 0
|
25
|
+
|
26
|
+
segments.keep_if { |seg| seg != '.' }
|
27
|
+
raise yield('Syntax error') unless segments.size * 2 == count + 1
|
28
|
+
segments.map! do |segment|
|
29
|
+
segment.strip!
|
30
|
+
segment.start_with?('"') || segment.start_with?("'") ? segment[1..-2] : segment
|
31
|
+
end
|
32
|
+
else
|
33
|
+
raise yield('Syntax error')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Perform a sub-lookup using the given _segments_ to access the given _value_. Each segment must be a string. A string
|
38
|
+
# consisting entirely of digits will be treated as an indexed lookup which means that the value that it is applied to
|
39
|
+
# must be an array. Other types of segments will expect that the given value is something other than a String that
|
40
|
+
# implements the '#[]' method.
|
41
|
+
#
|
42
|
+
# @param key [String] the original key (only used for error messages)
|
43
|
+
# @param lookup_invocation [Invocation] The current lookup invocation
|
44
|
+
# @param segments [Array<String>] the segments to use for lookup
|
45
|
+
# @param value [Object] the value to access using the segments
|
46
|
+
# @return [Object] the value obtained when accessing the value
|
47
|
+
#
|
48
|
+
# @api public
|
49
|
+
def sub_lookup(key, lookup_invocation, segments, value)
|
50
|
+
lookup_invocation.with(:sub_lookup, segments) do
|
51
|
+
segments.each do |segment|
|
52
|
+
lookup_invocation.with(:segment, segment) do
|
53
|
+
if value.nil?
|
54
|
+
lookup_invocation.report_not_found(segment)
|
55
|
+
throw :no_such_key
|
56
|
+
end
|
57
|
+
if segment =~ /^[0-9]+$/
|
58
|
+
segment = segment.to_i
|
59
|
+
unless value.instance_of?(Array)
|
60
|
+
raise Puppet::DataBinding::LookupError,
|
61
|
+
"Data Provider type mismatch: Got #{value.class.name} when Array was expected to access value using '#{segment}' from key '#{key}'"
|
62
|
+
end
|
63
|
+
unless segment < value.size
|
64
|
+
lookup_invocation.report_not_found(segment)
|
65
|
+
throw :no_such_key
|
66
|
+
end
|
67
|
+
else
|
68
|
+
unless value.respond_to?(:'[]') && !(value.instance_of?(Array) || value.instance_of?(String))
|
69
|
+
raise Puppet::DataBinding::LookupError,
|
70
|
+
"Data Provider type mismatch: Got #{value.class.name} when a hash-like object was expected to access value using '#{segment}' from key '#{key}'"
|
71
|
+
end
|
72
|
+
unless value.include?(segment)
|
73
|
+
lookup_invocation.report_not_found(segment)
|
74
|
+
throw :no_such_key
|
75
|
+
end
|
76
|
+
end
|
77
|
+
value = value[segment]
|
78
|
+
lookup_invocation.report_found(segment, value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
value
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|