puppet 4.8.2 → 4.9.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.
- checksums.yaml +15 -0
- data/CONTRIBUTING.md +25 -1
- data/Gemfile +6 -0
- data/Rakefile +1 -0
- data/ext/project_data.yaml +5 -1
- data/ext/windows/service/daemon.rb +2 -1
- data/install.rb +43 -6
- data/lib/hiera/puppet_function.rb +15 -17
- data/lib/hiera/scope.rb +12 -14
- data/lib/puppet.rb +52 -0
- data/lib/puppet/application/face_base.rb +4 -0
- data/lib/puppet/application/lookup.rb +4 -2
- data/lib/puppet/application/resource.rb +1 -1
- data/lib/puppet/data_providers.rb +6 -3
- data/lib/puppet/data_providers/data_adapter.rb +6 -0
- data/lib/puppet/data_providers/data_function_support.rb +7 -0
- data/lib/puppet/data_providers/function_env_data_provider.rb +7 -0
- data/lib/puppet/data_providers/function_module_data_provider.rb +6 -0
- data/lib/puppet/data_providers/hiera_config.rb +31 -10
- data/lib/puppet/data_providers/hiera_env_data_provider.rb +6 -0
- data/lib/puppet/data_providers/hiera_interpolate.rb +2 -1
- data/lib/puppet/data_providers/hiera_module_data_provider.rb +6 -0
- data/lib/puppet/data_providers/hiera_support.rb +6 -0
- data/lib/puppet/data_providers/json_data_provider_factory.rb +12 -0
- data/lib/puppet/data_providers/yaml_data_provider_factory.rb +12 -0
- data/lib/puppet/defaults.rb +25 -4
- data/lib/puppet/face/ca.rb +2 -0
- data/lib/puppet/face/certificate_request.rb +2 -0
- data/lib/puppet/face/certificate_revocation_list.rb +2 -0
- data/lib/puppet/face/file.rb +3 -0
- data/lib/puppet/face/help.rb +19 -17
- data/lib/puppet/face/help/face.erb +3 -0
- data/lib/puppet/face/key.rb +1 -0
- data/lib/puppet/face/man.rb +4 -2
- data/lib/puppet/face/module/generate.rb +1 -1
- data/lib/puppet/face/status.rb +2 -0
- data/lib/puppet/feature/base.rb +9 -2
- data/lib/puppet/feature/hocon.rb +3 -0
- data/lib/puppet/file_system.rb +15 -3
- data/lib/puppet/file_system/windows.rb +8 -0
- data/lib/puppet/forge.rb +6 -6
- data/lib/puppet/forge/repository.rb +1 -2
- data/lib/puppet/functions/binary_file.rb +4 -10
- data/lib/puppet/functions/hiera_array.rb +1 -1
- data/lib/puppet/functions/hiera_include.rb +1 -1
- data/lib/puppet/functions/hocon_data.rb +24 -0
- data/lib/puppet/functions/json_data.rb +18 -0
- data/lib/puppet/functions/yaml_data.rb +21 -0
- data/lib/puppet/generate/type.rb +1 -1
- data/lib/puppet/graph/simple_graph.rb +4 -2
- data/lib/puppet/indirector/file_bucket_file/file.rb +10 -2
- data/lib/puppet/indirector/request.rb +5 -1
- data/lib/puppet/interface.rb +14 -2
- data/lib/puppet/interface/face_collection.rb +1 -1
- data/lib/puppet/module.rb +14 -2
- data/lib/puppet/module_tool.rb +4 -4
- data/lib/puppet/module_tool/applications/builder.rb +3 -2
- data/lib/puppet/module_tool/applications/installer.rb +14 -14
- data/lib/puppet/module_tool/applications/upgrader.rb +13 -13
- data/lib/puppet/module_tool/installed_modules.rb +7 -7
- data/lib/puppet/module_tool/local_tarball.rb +3 -3
- data/lib/puppet/module_tool/metadata.rb +1 -1
- data/lib/puppet/network/http/connection.rb +2 -0
- data/lib/puppet/network/http/webrick.rb +2 -1
- data/lib/puppet/parser/functions/hiera.rb +14 -0
- data/lib/puppet/parser/functions/hiera_array.rb +14 -0
- data/lib/puppet/parser/functions/hiera_hash.rb +14 -0
- data/lib/puppet/parser/functions/hiera_include.rb +14 -0
- data/lib/puppet/parser/scope.rb +14 -20
- data/lib/puppet/plugins/data_providers.rb +2 -0
- data/lib/puppet/plugins/data_providers/data_provider.rb +108 -17
- data/lib/puppet/plugins/data_providers/registry.rb +2 -36
- data/lib/puppet/pops.rb +6 -9
- data/lib/puppet/pops/adaptable.rb +0 -3
- data/lib/puppet/pops/binder/producers.rb +3 -3
- data/lib/puppet/pops/evaluator/access_operator.rb +4 -4
- data/lib/puppet/pops/evaluator/closure.rb +1 -1
- data/lib/puppet/pops/evaluator/compare_operator.rb +4 -4
- data/lib/puppet/pops/evaluator/evaluator_impl.rb +1 -1
- data/lib/puppet/pops/issues.rb +4 -0
- data/lib/puppet/pops/label_provider.rb +14 -0
- data/lib/puppet/pops/loader/loader_paths.rb +3 -1
- data/lib/puppet/pops/loader/module_loaders.rb +21 -7
- data/lib/puppet/pops/loader/typed_name.rb +0 -2
- data/lib/puppet/pops/loaders.rb +31 -12
- data/lib/puppet/pops/lookup.rb +4 -3
- data/lib/puppet/pops/lookup/configured_data_provider.rb +87 -0
- data/lib/puppet/pops/lookup/context.rb +121 -71
- data/lib/puppet/pops/lookup/data_adapter.rb +27 -0
- data/lib/puppet/pops/lookup/data_dig_function_provider.rb +55 -0
- data/lib/puppet/pops/lookup/data_hash_function_provider.rb +111 -0
- data/lib/puppet/pops/lookup/data_provider.rb +102 -0
- data/lib/puppet/pops/lookup/environment_data_provider.rb +27 -0
- data/lib/puppet/pops/lookup/explainer.rb +122 -82
- data/lib/puppet/pops/lookup/function_provider.rb +82 -0
- data/lib/puppet/pops/lookup/global_data_provider.rb +49 -0
- data/lib/puppet/pops/lookup/hiera_config.rb +601 -0
- data/lib/puppet/pops/lookup/interpolation.rb +56 -35
- data/lib/puppet/pops/lookup/invocation.rb +179 -101
- data/lib/puppet/pops/lookup/location_resolver.rb +72 -0
- data/lib/puppet/pops/lookup/lookup_adapter.rb +451 -0
- data/lib/puppet/pops/lookup/lookup_key.rb +99 -0
- data/lib/puppet/pops/lookup/lookup_key_function_provider.rb +119 -0
- data/lib/puppet/pops/lookup/module_data_provider.rb +58 -0
- data/lib/puppet/pops/lookup/sub_lookup.rb +8 -4
- data/lib/puppet/pops/merge_strategy.rb +120 -39
- data/lib/puppet/pops/parser/egrammar.ra +2 -0
- data/lib/puppet/pops/parser/eparser.rb +816 -808
- data/lib/puppet/pops/parser/locator.rb +3 -3
- data/lib/puppet/pops/parser/slurp_support.rb +4 -3
- data/lib/puppet/pops/pcore.rb +21 -12
- data/lib/puppet/pops/serialization/abstract_reader.rb +17 -7
- data/lib/puppet/pops/serialization/abstract_writer.rb +27 -12
- data/lib/puppet/pops/serialization/deserializer.rb +17 -4
- data/lib/puppet/pops/serialization/extension.rb +37 -8
- data/lib/puppet/pops/serialization/object.rb +14 -6
- data/lib/puppet/pops/serialization/rgen.rb +2 -1
- data/lib/puppet/pops/serialization/serializer.rb +30 -7
- data/lib/puppet/pops/types/implementation_registry.rb +1 -1
- data/lib/puppet/pops/types/p_object_type.rb +55 -12
- data/lib/puppet/pops/types/p_sem_ver_range_type.rb +27 -27
- data/lib/puppet/pops/types/p_sem_ver_type.rb +12 -12
- data/lib/puppet/pops/types/p_timespan_type.rb +6 -6
- data/lib/puppet/pops/types/p_timestamp_type.rb +2 -2
- data/lib/puppet/pops/types/p_type_set_type.rb +7 -16
- data/lib/puppet/pops/types/recursion_guard.rb +64 -20
- data/lib/puppet/pops/types/ruby_generator.rb +10 -0
- data/lib/puppet/pops/types/type_calculator.rb +23 -13
- data/lib/puppet/pops/types/type_factory.rb +20 -9
- data/lib/puppet/pops/types/type_formatter.rb +37 -17
- data/lib/puppet/pops/types/type_mismatch_describer.rb +7 -6
- data/lib/puppet/pops/types/type_parser.rb +6 -0
- data/lib/puppet/pops/types/types.rb +225 -132
- data/lib/puppet/pops/validation.rb +1 -1
- data/lib/puppet/pops/validation/checker4_0.rb +12 -2
- data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
- data/lib/puppet/pops/visitor.rb +4 -3
- data/lib/puppet/provider/mcx/mcxcontent.rb +2 -1
- data/lib/puppet/provider/nameservice.rb +15 -0
- data/lib/puppet/provider/package/appdmg.rb +1 -1
- data/lib/puppet/provider/package/dnf.rb +1 -1
- data/lib/puppet/provider/package/pkg.rb +1 -1
- data/lib/puppet/provider/package/pkgdmg.rb +1 -1
- data/lib/puppet/provider/package/pkgng.rb +1 -1
- data/lib/puppet/provider/package/rpm.rb +2 -2
- data/lib/puppet/provider/service/smf.rb +3 -3
- data/lib/puppet/provider/service/systemd.rb +5 -1
- data/lib/puppet/provider/user/directoryservice.rb +1 -0
- data/lib/puppet/provider/user/user_role_add.rb +15 -0
- data/lib/puppet/provider/yumrepo/inifile.rb +2 -2
- data/lib/puppet/provider/zone/solaris.rb +4 -1
- data/lib/puppet/reference/indirection.rb +1 -1
- data/lib/puppet/resource.rb +2 -3
- data/lib/puppet/resource/catalog.rb +12 -4
- data/lib/puppet/resource/type.rb +3 -3
- data/lib/puppet/settings.rb +1 -1
- data/lib/puppet/settings/config_file.rb +2 -1
- data/lib/puppet/settings/directory_setting.rb +6 -0
- data/lib/puppet/settings/environment_conf.rb +6 -2
- data/lib/puppet/settings/file_or_directory_setting.rb +6 -0
- data/lib/puppet/settings/file_setting.rb +10 -0
- data/lib/puppet/ssl/certificate_authority.rb +13 -2
- data/lib/puppet/ssl/host.rb +23 -1
- data/lib/puppet/transaction/additional_resource_generator.rb +7 -0
- data/lib/puppet/type/user.rb +16 -3
- data/lib/puppet/util.rb +1 -0
- data/lib/puppet/util/execution.rb +3 -3
- data/lib/puppet/util/filetype.rb +11 -5
- data/lib/puppet/util/logging.rb +2 -1
- data/lib/puppet/util/network_device/config.rb +1 -1
- data/lib/puppet/util/plist.rb +6 -0
- data/lib/puppet/util/profiler/aggregate.rb +1 -1
- data/lib/puppet/util/rdoc/generators/puppet_generator.rb +2 -2
- data/lib/puppet/util/rdoc/parser/puppet_parser_core.rb +2 -1
- data/lib/puppet/util/windows/adsi.rb +15 -12
- data/lib/puppet/vendor/load_semantic_puppet.rb +1 -0
- data/lib/puppet/vendor/pathspec/lib/pathspec.rb +2 -1
- data/lib/puppet/vendor/require_vendored.rb +0 -1
- data/lib/puppet/vendor/semantic_puppet/lib/semantic_puppet.rb +17 -0
- data/lib/puppet/vendor/{semantic/lib/semantic → semantic_puppet/lib/semantic_puppet}/dependency.rb +7 -7
- data/lib/puppet/vendor/{semantic/lib/semantic → semantic_puppet/lib/semantic_puppet}/dependency/graph.rb +2 -2
- data/lib/puppet/vendor/{semantic/lib/semantic → semantic_puppet/lib/semantic_puppet}/dependency/graph_node.rb +2 -2
- data/lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/dependency/module_release.rb +58 -0
- data/lib/puppet/vendor/{semantic/lib/semantic → semantic_puppet/lib/semantic_puppet}/dependency/source.rb +2 -2
- data/lib/puppet/vendor/{semantic/lib/semantic → semantic_puppet/lib/semantic_puppet}/dependency/unsatisfiable_graph.rb +2 -2
- data/lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/gem_version.rb +3 -0
- data/lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/locales/config.yaml +21 -0
- data/lib/puppet/vendor/{semantic/lib/semantic → semantic_puppet/lib/semantic_puppet}/version.rb +48 -21
- data/lib/puppet/vendor/{semantic/lib/semantic → semantic_puppet/lib/semantic_puppet}/version_range.rb +15 -17
- data/lib/puppet/version.rb +1 -1
- data/lib/semver.rb +19 -12
- data/locales/config.yaml +29 -0
- data/locales/puppet.pot +79 -0
- data/man/man5/puppet.conf.5 +1 -1
- data/spec/fixtures/unit/application/environments/puppet_func_provider/functions/{data.pp → environment/data.pp} +0 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_misc/data/common.yaml +2 -0
- data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/two/data/common.yaml +1 -1
- data/spec/fixtures/unit/data_providers/environments/sample/modules/backend/hiera.yaml +5 -0
- data/spec/fixtures/unit/data_providers/environments/sample/modules/backend/lib/puppet/bindings/backend/default.rb +9 -0
- data/spec/fixtures/unit/data_providers/environments/sample/modules/backend/lib/puppet_x/backend/special_data_provider_factory.rb +23 -0
- data/spec/fixtures/unit/data_providers/environments/sample/modules/backend/manifests/init.pp +5 -0
- data/spec/fixtures/unit/data_providers/environments/sample/modules/backend/metadata.json +9 -0
- data/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/lib/puppet_x/helindbe/sample_env_data.rb +1 -0
- data/spec/fixtures/unit/data_providers/environments/sample/modules/dataprovider/manifests/init.pp +1 -1
- data/spec/fixtures/unit/functions/lookup/data/common.yaml +19 -0
- data/spec/fixtures/unit/functions/lookup_fixture/data/common.yaml +19 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/environment.conf +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/lib/puppet/functions/environment/data.rb +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/abc/lib/puppet/bindings/abc/default.rb +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/abc/lib/puppet/functions/abc/data.rb +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/abc/manifests/init.pp +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/bad_data/lib/puppet/bindings/bad_data/default.rb +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/bad_data/lib/puppet/functions/bad_data/data.rb +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/bad_data/manifests/init.pp +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/bca/lib/puppet/bindings/bca/default.rb +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/bca/lib/puppet/functions/bca/data.rb +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/bca/manifests/init.pp +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_json/data/empty.json +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_json/hiera.yaml +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_json/manifests/init.pp +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_json/metadata.json +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_key_json/data/empty_key.json +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_key_json/hiera.yaml +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_key_json/manifests/init.pp +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_key_json/metadata.json +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_key_yaml/data/empty_key.yaml +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_key_yaml/hiera.yaml +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_key_yaml/manifests/init.pp +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_key_yaml/metadata.json +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_yaml/data/empty.yaml +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_yaml/hiera.yaml +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_yaml/manifests/init.pp +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/empty_yaml/metadata.json +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/hieraprovider/data/first.json +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/hieraprovider/hiera.yaml +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/hieraprovider/manifests/init.pp +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/hieraprovider/metadata.json +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/meta/lib/puppet/functions/meta/data.rb +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/meta/manifests/init.pp +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/meta/metadata.json +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/metawcp/lib/puppet/bindings/metawcp/default.rb +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/metawcp/lib/puppet_x/thallgren/sample_module_data.rb +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/metawcp/manifests/init.pp +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/metawcp/metadata.json +0 -0
- data/spec/fixtures/unit/functions/{lookup → lookup_fixture}/environments/production/modules/no_provider/manifests/init.pp +0 -0
- data/spec/integration/application/apply_spec.rb +88 -2
- data/spec/integration/application/lookup_spec.rb +155 -0
- data/spec/integration/data_binding_spec.rb +5 -5
- data/spec/integration/defaults_spec.rb +13 -0
- data/spec/integration/environments/default_manifest_spec.rb +16 -16
- data/spec/integration/environments/setting_hooks_spec.rb +1 -1
- data/spec/integration/test/test_helper_spec.rb +6 -2
- data/spec/integration/transaction_spec.rb +74 -0
- data/spec/integration/util/execution_spec.rb +8 -0
- data/spec/lib/puppet_spec/module_tool/shared_functions.rb +2 -2
- data/spec/lib/puppet_spec/module_tool/stub_source.rb +1 -1
- data/spec/lib/puppet_spec/unindent.rb +2 -2
- data/spec/unit/application/face_base_spec.rb +16 -0
- data/spec/unit/application/lookup_spec.rb +262 -227
- data/spec/unit/data_providers/{sample_data_provider_spec.rb → custom_data_provider_spec.rb} +14 -16
- data/spec/unit/data_providers/function_data_provider_spec.rb +2 -2
- data/spec/unit/data_providers/hiera_data_provider_spec.rb +60 -97
- data/spec/unit/defaults_spec.rb +1 -1
- data/spec/unit/face/ca_spec.rb +10 -0
- data/spec/unit/face/certificate_request_spec.rb +10 -0
- data/spec/unit/face/certificate_revocation_list_spec.rb +10 -0
- data/spec/unit/face/file_spec.rb +4 -0
- data/spec/unit/face/help_spec.rb +17 -0
- data/spec/unit/face/key_spec.rb +10 -0
- data/spec/unit/face/status_spec.rb +10 -0
- data/spec/unit/file_system_spec.rb +143 -6
- data/spec/unit/functions/binary_file_spec.rb +1 -1
- data/spec/unit/functions/hiera_spec.rb +257 -47
- data/spec/unit/functions/lookup_fixture_spec.rb +693 -0
- data/spec/unit/functions/lookup_spec.rb +1319 -608
- data/spec/unit/functions/new_spec.rb +3 -3
- data/spec/unit/graph/rb_tree_map_spec.rb +1 -1
- data/spec/unit/graph/simple_graph_spec.rb +1 -1
- data/spec/unit/hiera/scope_spec.rb +4 -4
- data/spec/unit/indirector/request_spec.rb +9 -0
- data/spec/unit/interface_spec.rb +27 -0
- data/spec/unit/man_spec.rb +1 -1
- data/spec/unit/module_spec.rb +1 -1
- data/spec/unit/module_tool/applications/builder_spec.rb +16 -1
- data/spec/unit/module_tool/applications/installer_spec.rb +1 -1
- data/spec/unit/module_tool/applications/upgrader_spec.rb +1 -1
- data/spec/unit/module_tool/installed_modules_spec.rb +6 -6
- data/spec/unit/module_tool_spec.rb +3 -3
- data/spec/unit/network/http/connection_spec.rb +10 -0
- data/spec/unit/network/http/webrick_spec.rb +1 -1
- data/spec/unit/pops/evaluator/access_ops_spec.rb +2 -2
- data/spec/unit/pops/evaluator/runtime3_converter_spec.rb +9 -9
- data/spec/unit/pops/loaders/environment_loader_spec.rb +172 -0
- data/spec/unit/pops/lookup/context_spec.rb +45 -16
- data/spec/unit/pops/lookup/interpolation_spec.rb +28 -20
- data/spec/unit/pops/lookup/lookup_spec.rb +197 -0
- data/spec/unit/pops/merge_strategy_spec.rb +18 -0
- data/spec/unit/pops/parser/lexer2_spec.rb +16 -1
- data/spec/unit/pops/parser/parse_site_spec.rb +4 -0
- data/spec/unit/pops/serialization/packer_spec.rb +4 -23
- data/spec/unit/pops/serialization/serialization_spec.rb +32 -8
- data/spec/unit/pops/types/p_object_type_spec.rb +68 -3
- data/spec/unit/pops/types/p_sem_ver_type_spec.rb +4 -4
- data/spec/unit/pops/types/p_type_set_type_spec.rb +31 -2
- data/spec/unit/pops/types/type_acceptor_spec.rb +18 -17
- data/spec/unit/pops/types/type_calculator_spec.rb +39 -40
- data/spec/unit/pops/types/type_factory_spec.rb +3 -3
- data/spec/unit/pops/types/type_formatter_spec.rb +7 -3
- data/spec/unit/pops/types/type_mismatch_describer_spec.rb +13 -2
- data/spec/unit/pops/types/types_spec.rb +25 -2
- data/spec/unit/pops/validator/validator_spec.rb +60 -4
- data/spec/unit/provider/nameservice_spec.rb +42 -0
- data/spec/unit/provider/package/aptrpm_spec.rb +1 -1
- data/spec/unit/provider/package/pkg_spec.rb +22 -0
- data/spec/unit/provider/package/pkgng_spec.rb +12 -0
- data/spec/unit/provider/package/rpm_spec.rb +8 -8
- data/spec/unit/provider/service/smf_spec.rb +13 -11
- data/spec/unit/provider/service/systemd_spec.rb +8 -1
- data/spec/unit/provider/user/useradd_spec.rb +1 -0
- data/spec/unit/puppet_spec.rb +14 -0
- data/spec/unit/resource/catalog_spec.rb +15 -9
- data/spec/unit/resource_spec.rb +20 -17
- data/spec/unit/semver_spec.rb +14 -0
- data/spec/unit/ssl/certificate_authority_spec.rb +12 -1
- data/spec/unit/transaction/additional_resource_generator_spec.rb +11 -0
- data/spec/unit/type/user_spec.rb +32 -6
- data/spec/unit/util/filetype_spec.rb +3 -3
- data/spec/unit/util/yaml_spec.rb +1 -1
- data/spec/unit/util_spec.rb +10 -2
- data/tasks/i18n.rake +20 -0
- metadata +2661 -2593
- data/lib/puppet/data_providers/lookup_adapter.rb +0 -254
- data/lib/puppet/vendor/load_semantic.rb +0 -1
- data/lib/puppet/vendor/semantic/Gemfile +0 -20
- data/lib/puppet/vendor/semantic/PUPPET_README.md +0 -6
- data/lib/puppet/vendor/semantic/Rakefile +0 -69
- data/lib/puppet/vendor/semantic/lib/semantic.rb +0 -7
- data/lib/puppet/vendor/semantic/lib/semantic/dependency/module_release.rb +0 -60
- data/lib/puppet/vendor/semantic/spec/spec_helper.rb +0 -24
- data/lib/puppet/vendor/semantic/spec/unit/semantic/dependency/graph_node_spec.rb +0 -141
- data/lib/puppet/vendor/semantic/spec/unit/semantic/dependency/graph_spec.rb +0 -162
- data/lib/puppet/vendor/semantic/spec/unit/semantic/dependency/module_release_spec.rb +0 -143
- data/lib/puppet/vendor/semantic/spec/unit/semantic/dependency/source_spec.rb +0 -5
- data/lib/puppet/vendor/semantic/spec/unit/semantic/dependency/unsatisfiable_graph_spec.rb +0 -44
- data/lib/puppet/vendor/semantic/spec/unit/semantic/dependency_spec.rb +0 -383
- data/lib/puppet/vendor/semantic/spec/unit/semantic/version_range_spec.rb +0 -307
- data/lib/puppet/vendor/semantic/spec/unit/semantic/version_spec.rb +0 -608
- data/spec/fixtures/unit/data_providers/environments/sample/manifests/site.pp +0 -6
@@ -1,733 +1,1444 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
2
|
require 'spec_helper'
|
3
3
|
require 'puppet_spec/compiler'
|
4
|
+
require 'puppet_spec/files'
|
4
5
|
require 'puppet/pops'
|
6
|
+
require 'deep_merge/core'
|
5
7
|
|
6
|
-
describe "
|
8
|
+
describe "The lookup function" do
|
7
9
|
include PuppetSpec::Compiler
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
# There is a fully configured 'production' environment in fixtures at this location
|
51
|
-
let(:environmentpath) { File.join(my_fixture_dir, 'environments') }
|
52
|
-
let(:node) { Puppet::Node.new("testnode", :facts => Puppet::Node::Facts.new("facts", {}), :environment => 'production') }
|
53
|
-
let(:compiler) { Puppet::Parser::Compiler.new(node) }
|
54
|
-
|
55
|
-
around(:each) do |example|
|
56
|
-
# Initialize settings to get a full compile as close as possible to a real
|
57
|
-
# environment load
|
58
|
-
Puppet.settings.initialize_global_settings
|
59
|
-
|
60
|
-
# Initialize loaders based on the environmentpath. It does not work to
|
61
|
-
# just set the setting environmentpath for some reason - this achieves the same:
|
62
|
-
# - first a loader is created, loading directory environments from the fixture (there is
|
63
|
-
# one environment, 'sample', which will be loaded since the node references this
|
64
|
-
# environment by name).
|
65
|
-
# - secondly, the created env loader is set as 'environments' in the puppet context.
|
66
|
-
#
|
67
|
-
environments = Puppet::Environments::Directories.new(environmentpath, [])
|
68
|
-
Puppet.override(:environments => environments) do
|
69
|
-
example.run
|
10
|
+
include PuppetSpec::Files
|
11
|
+
|
12
|
+
context 'with an environment' do
|
13
|
+
let(:env_name) { 'spec' }
|
14
|
+
let(:code_dir_files) { {} }
|
15
|
+
let(:code_dir) { tmpdir('code') }
|
16
|
+
let(:environment_files) do
|
17
|
+
{
|
18
|
+
env_name => {
|
19
|
+
'modules' => {},
|
20
|
+
'hiera.yaml' => <<-YAML.unindent,
|
21
|
+
---
|
22
|
+
version: 5
|
23
|
+
hierarchy:
|
24
|
+
- name: "Common"
|
25
|
+
data_hash: yaml_data
|
26
|
+
path: "common.yaml"
|
27
|
+
YAML
|
28
|
+
'data' => {
|
29
|
+
'common.yaml' => <<-YAML.unindent
|
30
|
+
---
|
31
|
+
a: value a
|
32
|
+
mod_a::a: value mod_a::a (from environment)
|
33
|
+
mod_a::hash_a:
|
34
|
+
a: value mod_a::hash_a.a (from environment)
|
35
|
+
mod_a::hash_b:
|
36
|
+
a: value mod_a::hash_b.a (from environment)
|
37
|
+
hash_b:
|
38
|
+
hash_ba:
|
39
|
+
bab: value hash_b.hash_ba.bab (from environment)
|
40
|
+
hash_c:
|
41
|
+
hash_ca:
|
42
|
+
caa: value hash_c.hash_ca.caa (from environment)
|
43
|
+
lookup_options:
|
44
|
+
mod_a::hash_b:
|
45
|
+
merge: hash
|
46
|
+
hash_c:
|
47
|
+
merge: hash
|
48
|
+
YAML
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
70
52
|
end
|
71
|
-
end
|
72
53
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
54
|
+
let(:logs) { [] }
|
55
|
+
let(:notices) { logs.select { |log| log.level == :notice }.map { |log| log.message } }
|
56
|
+
let(:warnings) { logs.select { |log| log.level == :warning }.map { |log| log.message } }
|
57
|
+
let(:debugs) { logs.select { |log| log.level == :debug }.map { |log| log.message } }
|
58
|
+
let(:env) { Puppet::Node::Environment.create(env_name.to_sym, [File.join(populated_env_dir, env_name, 'modules')]) }
|
59
|
+
let(:environments) { Puppet::Environments::Directories.new(populated_env_dir, []) }
|
60
|
+
let(:node) { Puppet::Node.new('test_lookup', :environment => env) }
|
61
|
+
let(:compiler) { Puppet::Parser::Compiler.new(node) }
|
62
|
+
let(:lookup_func) { Puppet.lookup(:loaders).puppet_system_loader.load(:function, 'lookup') }
|
63
|
+
let(:defaults) {
|
64
|
+
{
|
65
|
+
'mod_a::xd' => 'value mod_a::xd (from default)',
|
66
|
+
'mod_a::xd_found' => 'value mod_a::xd_found (from default)',
|
67
|
+
'scope_xd' => 'value scope_xd (from default)'
|
68
|
+
}}
|
69
|
+
let(:overrides) {
|
70
|
+
{
|
71
|
+
'mod_a::xo' => 'value mod_a::xo (from override)',
|
72
|
+
'scope_xo' => 'value scope_xo (from override)'
|
73
|
+
}}
|
74
|
+
let(:invocation_with_explain) { Puppet::Pops::Lookup::Invocation.new(compiler.topscope, {}, {}, true) }
|
75
|
+
let(:explanation) { invocation_with_explain.explainer.explain }
|
76
|
+
|
77
|
+
let(:populated_code_dir) do
|
78
|
+
dir_contained_in(code_dir, code_dir_files)
|
79
|
+
code_dir
|
77
80
|
end
|
78
81
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
+
let(:env_dir) do
|
83
|
+
d = File.join(populated_code_dir, 'environments')
|
84
|
+
Dir.mkdir(d)
|
85
|
+
d
|
82
86
|
end
|
83
87
|
|
84
|
-
|
85
|
-
|
86
|
-
|
88
|
+
let(:populated_env_dir) do
|
89
|
+
dir_contained_in(env_dir, environment_files)
|
90
|
+
env_dir
|
87
91
|
end
|
88
92
|
|
89
|
-
|
90
|
-
|
91
|
-
|
93
|
+
before(:each) do
|
94
|
+
Puppet.settings[:codedir] = code_dir
|
95
|
+
Puppet.push_context(:environments => environments, :current_environment => env)
|
92
96
|
end
|
93
97
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
98
|
+
after(:each) do
|
99
|
+
Puppet.pop_context
|
100
|
+
if Object.const_defined?(:Hiera)
|
101
|
+
Hiera.send(:remove_instance_variable, :@config) if Hiera.instance_variable_defined?(:@config)
|
102
|
+
Hiera.send(:remove_instance_variable, :@logger) if Hiera.instance_variable_defined?(:@logger)
|
103
|
+
if Hiera.const_defined?(:Config)
|
104
|
+
Hiera::Config.send(:remove_instance_variable, :@config) if Hiera::Config.instance_variable_defined?(:@config)
|
105
|
+
end
|
106
|
+
if Hiera.const_defined?(:Backend)
|
107
|
+
Hiera::Backend.clear!
|
108
|
+
end
|
109
|
+
end
|
99
110
|
end
|
100
111
|
|
101
|
-
|
102
|
-
|
103
|
-
|
112
|
+
def collect_notices(code, explain = false, &block)
|
113
|
+
Puppet[:code] = code
|
114
|
+
Puppet::Util::Log.with_destination(Puppet::Test::LogCollector.new(logs)) do
|
115
|
+
scope = compiler.topscope
|
116
|
+
scope['environment'] = env_name
|
117
|
+
scope['domain'] = 'example.com'
|
118
|
+
scope['scope_scalar'] = 'scope scalar value'
|
119
|
+
scope['scope_hash'] = { 'a' => 'scope hash a', 'b' => 'scope hash b' }
|
120
|
+
if explain
|
121
|
+
begin
|
122
|
+
invocation_with_explain.lookup('dummy', nil) do
|
123
|
+
if block_given?
|
124
|
+
compiler.compile { |catalog| block.call(compiler.topscope); catalog }
|
125
|
+
else
|
126
|
+
compiler.compile
|
127
|
+
end
|
128
|
+
end
|
129
|
+
rescue Puppet::DataBinding::LookupError => e
|
130
|
+
invocation_with_explain.report_text { e.message }
|
131
|
+
end
|
132
|
+
else
|
133
|
+
if block_given?
|
134
|
+
compiler.compile { |catalog| block.call(compiler.topscope); catalog }
|
135
|
+
else
|
136
|
+
compiler.compile
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
nil
|
104
141
|
end
|
105
142
|
|
106
|
-
|
107
|
-
|
108
|
-
|
143
|
+
def lookup(key, options = {}, explain = false)
|
144
|
+
nc_opts = options.empty? ? '' : ", #{Puppet::Pops::Types::TypeFormatter.string(options)}"
|
145
|
+
keys = key.is_a?(Array) ? key : [key]
|
146
|
+
collect_notices(keys.map { |k| "notice(String(lookup('#{k}'#{nc_opts}), '%p'))" }.join("\n"), explain)
|
147
|
+
if explain
|
148
|
+
explanation
|
149
|
+
else
|
150
|
+
result = notices.map { |n| Puppet::Pops::Types::TypeParser.singleton.parse_literal(n) }
|
151
|
+
key.is_a?(Array) ? result : result[0]
|
152
|
+
end
|
109
153
|
end
|
110
154
|
|
111
|
-
|
112
|
-
|
113
|
-
|
155
|
+
def explain(key, options = {})
|
156
|
+
lookup(key, options, true)[1]
|
157
|
+
explanation
|
114
158
|
end
|
115
159
|
|
116
|
-
it
|
117
|
-
|
118
|
-
expect(resources).to include('env_d1_env_d2_env_d3')
|
160
|
+
it 'finds data in the environment' do
|
161
|
+
expect(lookup('a')).to eql('value a')
|
119
162
|
end
|
120
163
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
164
|
+
context 'that has no lookup configured' do
|
165
|
+
let(:environment_files) do
|
166
|
+
{
|
167
|
+
env_name => {
|
168
|
+
'modules' => {},
|
169
|
+
'data' => {
|
170
|
+
'common.yaml' => <<-YAML.unindent
|
171
|
+
---
|
172
|
+
a: value a
|
173
|
+
YAML
|
174
|
+
}
|
175
|
+
}
|
176
|
+
}
|
177
|
+
end
|
125
178
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
resources = assemble_and_compile('${r[k1]}_${r[k2]}_${r[k3]}', "'abc::e'", 'Hash[String,String]', "'hash'")
|
130
|
-
expect(resources).to include('global_e1_module_e2_env_e3')
|
131
|
-
end
|
179
|
+
it 'does not find data in the environment' do
|
180
|
+
expect { lookup('a') }.to raise_error(Puppet::DataBinding::LookupError, /did not find a value for the name 'a'/)
|
181
|
+
end
|
132
182
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
183
|
+
context "but an environment.conf with 'environment_data_provider=hiera'" do
|
184
|
+
let(:environment_files_1) do
|
185
|
+
DeepMerge.deep_merge!(environment_files, 'environment.conf' => "environment_data_provider=hiera\n")
|
186
|
+
end
|
137
187
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
188
|
+
let(:populated_env_dir) do
|
189
|
+
dir_contained_in(env_dir, DeepMerge.deep_merge!(environment_files, env_name => environment_files_1))
|
190
|
+
env_dir
|
191
|
+
end
|
142
192
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
193
|
+
it 'finds data in the environment and reports deprecation warning for environment.conf' do
|
194
|
+
expect(lookup('a')).to eql('value a')
|
195
|
+
expect(warnings).to include(/Defining environment_data_provider='hiera' in environment.conf is deprecated. A 'hiera.yaml' file should be used instead/)
|
196
|
+
end
|
147
197
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
198
|
+
context 'and a hiera.yaml file' do
|
199
|
+
let(:environment_files_2) { DeepMerge.deep_merge!(environment_files_1,'hiera.yaml' => <<-YAML.unindent) }
|
200
|
+
---
|
201
|
+
version: 4
|
202
|
+
hierarchy:
|
203
|
+
- name: common
|
204
|
+
backend: yaml
|
205
|
+
YAML
|
206
|
+
|
207
|
+
let(:populated_env_dir) do
|
208
|
+
dir_contained_in(env_dir, DeepMerge.deep_merge!(environment_files, env_name => environment_files_2))
|
209
|
+
env_dir
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'finds data in the environment and reports deprecation warnings for both environment.conf and hiera.yaml' do
|
213
|
+
expect(lookup('a')).to eql('value a')
|
214
|
+
expect(warnings).to include(/Defining environment_data_provider='hiera' in environment.conf is deprecated/)
|
215
|
+
expect(warnings).to include(/Use of 'hiera.yaml' version 4 is deprecated. It should be converted to version 5/)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
153
219
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
220
|
+
context "but an environment.conf with 'environment_data_provider=function'" do
|
221
|
+
let(:environment_files) do
|
222
|
+
{
|
223
|
+
env_name => {
|
224
|
+
'environment.conf' => "environment_data_provider=function\n",
|
225
|
+
'functions' => {
|
226
|
+
'environment' => { 'data.pp' => <<-PUPPET.unindent }
|
227
|
+
function environment::data() {
|
228
|
+
{ 'a' => 'value a' }
|
229
|
+
}
|
230
|
+
PUPPET
|
231
|
+
}
|
232
|
+
}
|
233
|
+
}
|
234
|
+
end
|
159
235
|
|
160
|
-
|
161
|
-
|
162
|
-
|
236
|
+
it 'finds data in the environment and reports deprecation warning for environment.conf' do
|
237
|
+
expect(lookup('a')).to eql('value a')
|
238
|
+
expect(warnings).to include(/Defining environment_data_provider='function' in environment.conf is deprecated. A 'hiera.yaml' file should be used instead/)
|
239
|
+
expect(warnings).to include(/Using of legacy data provider function 'environment::data'. Please convert to a 'data_hash' function/)
|
240
|
+
end
|
241
|
+
end
|
163
242
|
end
|
164
243
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
244
|
+
context 'that has interpolated paths configured' do
|
245
|
+
let(:environment_files) do
|
246
|
+
{
|
247
|
+
env_name => {
|
248
|
+
'hiera.yaml' => <<-YAML.unindent,
|
249
|
+
---
|
250
|
+
version: 5
|
251
|
+
hierarchy:
|
252
|
+
- name: "Varying"
|
253
|
+
data_hash: yaml_data
|
254
|
+
path: "x%{::var}.yaml"
|
255
|
+
YAML
|
256
|
+
'modules' => {},
|
257
|
+
'data' => {
|
258
|
+
'x.yaml' => <<-YAML.unindent,
|
259
|
+
y: value y from x
|
260
|
+
YAML
|
261
|
+
'x_d.yaml' => <<-YAML.unindent
|
262
|
+
y: value y from x_d
|
263
|
+
YAML
|
264
|
+
}
|
265
|
+
}
|
266
|
+
}
|
267
|
+
end
|
169
268
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
269
|
+
it 'reloads the configuration if interpolated values change' do
|
270
|
+
Puppet[:log_level] = 'debug'
|
271
|
+
collect_notices("notice('success')") do |scope|
|
272
|
+
expect(lookup_func.call(scope, 'y')).to eql('value y from x')
|
273
|
+
scope['var'] = '_d'
|
274
|
+
expect(lookup_func.call(scope, 'y')).to eql('value y from x_d')
|
275
|
+
end
|
276
|
+
expect(notices).to eql(['success'])
|
277
|
+
expect(debugs.any? { |m| m =~ /Hiera configuration recreated due to change of scope variables used in interpolation expressions/ }).to be_truthy
|
278
|
+
end
|
174
279
|
end
|
175
280
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
281
|
+
context 'that uses reserved option' do
|
282
|
+
let(:environment_files) do
|
283
|
+
{
|
284
|
+
env_name => {
|
285
|
+
'hiera.yaml' => <<-YAML.unindent,
|
286
|
+
---
|
287
|
+
version: 5
|
288
|
+
hierarchy:
|
289
|
+
- name: "Illegal"
|
290
|
+
options:
|
291
|
+
#{opt_spec}
|
292
|
+
data_hash: yaml_data
|
293
|
+
YAML
|
294
|
+
'data' => {
|
295
|
+
'foo.yaml' => "a: The value a\n"
|
296
|
+
}
|
297
|
+
}
|
298
|
+
}
|
299
|
+
end
|
181
300
|
|
182
|
-
|
183
|
-
|
184
|
-
expect(resources).to include('env_d1_env_d2_env_d3')
|
185
|
-
end
|
301
|
+
context 'path' do
|
302
|
+
let(:opt_spec) { 'path: data/foo.yaml' }
|
186
303
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
304
|
+
it 'fails and reports the reserved option key' do
|
305
|
+
expect { lookup('a') }.to raise_error do |e|
|
306
|
+
expect(e.message).to match(/Option key 'path' used in hierarchy 'Illegal' is reserved by Puppet/)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
191
310
|
|
192
|
-
|
193
|
-
|
194
|
-
Hiera.any_instance.expects(:lookup).with('abc::f', any_parameters).returns({ 'k1' => { 's1' => 'global_f11' }, 'k2' => { 's3' => 'global_f23' }})
|
195
|
-
resources = assemble_and_compile('${r[k1][s1]}_${r[k1][s2]}_${r[k1][s3]}_${r[k2][s1]}_${r[k2][s2]}_${r[k2][s3]}', "'abc::f'", 'Hash[String,Hash[String,String]]', "'deep'")
|
196
|
-
expect(resources).to include('global_f11_env_f12_module_f13_env_f21_module_f22_global_f23')
|
197
|
-
end
|
311
|
+
context 'uri' do
|
312
|
+
let(:opt_spec) { 'uri: file:///data/foo.yaml' }
|
198
313
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
314
|
+
it 'fails and reports the reserved option key' do
|
315
|
+
expect { lookup('a') }.to raise_error do |e|
|
316
|
+
expect(e.message).to match(/Option key 'uri' used in hierarchy 'Illegal' is reserved by Puppet/)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
204
320
|
end
|
205
321
|
|
206
|
-
it 'will propagate a Hash resolution_type with :behavior => :native to Hiera when merge == \'hash\'' do
|
207
|
-
Hiera.any_instance.expects(:lookup).with('lookup_options', any_parameters).at_most_once.throws(:no_such_key)
|
208
|
-
Hiera.any_instance.expects(:lookup).with('abc::e', anything, anything, anything, { :behavior => :native }).returns({ 'k1' => 'global_e1' })
|
209
|
-
resources = assemble_and_compile('${r[k1]}_${r[k2]}_${r[k3]}', "'abc::e'", 'Hash[String,String]', "{strategy => 'hash'}")
|
210
|
-
expect(resources).to include('global_e1_module_e2_env_e3')
|
211
|
-
end
|
212
322
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
323
|
+
context 'with lookup_options configured using patterns' do
|
324
|
+
let(:mod_common) {
|
325
|
+
<<-YAML.unindent
|
326
|
+
mod::hash_a:
|
327
|
+
aa:
|
328
|
+
aaa: aaa (from module)
|
329
|
+
ab:
|
330
|
+
aba: aba (from module)
|
331
|
+
mod::hash_b:
|
332
|
+
ba:
|
333
|
+
baa: baa (from module)
|
334
|
+
bb:
|
335
|
+
bba: bba (from module)
|
336
|
+
lookup_options:
|
337
|
+
'^mod::ha.*_a':
|
338
|
+
merge: deep
|
339
|
+
'^mod::ha.*_b':
|
340
|
+
merge: deep
|
341
|
+
YAML
|
342
|
+
}
|
219
343
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
344
|
+
let(:mod_base) do
|
345
|
+
{
|
346
|
+
'hiera.yaml' => <<-YAML.unindent,
|
347
|
+
version: 5
|
348
|
+
YAML
|
349
|
+
'data' => {
|
350
|
+
'common.yaml' => mod_common
|
351
|
+
}
|
352
|
+
}
|
353
|
+
end
|
226
354
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
355
|
+
let(:environment_files) do
|
356
|
+
{
|
357
|
+
env_name => {
|
358
|
+
'hiera.yaml' => <<-YAML.unindent,
|
359
|
+
---
|
360
|
+
version: 5
|
361
|
+
hierarchy:
|
362
|
+
- name: X
|
363
|
+
paths:
|
364
|
+
- first.yaml
|
365
|
+
- second.yaml
|
366
|
+
YAML
|
367
|
+
'data' => {
|
368
|
+
'first.yaml' => <<-YAML.unindent,
|
369
|
+
a:
|
370
|
+
aa:
|
371
|
+
aaa: a.aa.aaa
|
372
|
+
b:
|
373
|
+
ba:
|
374
|
+
baa: b.ba.baa
|
375
|
+
bb:
|
376
|
+
bba: b.bb.bba
|
377
|
+
c:
|
378
|
+
ca:
|
379
|
+
caa: c.ca.caa
|
380
|
+
mod::hash_a:
|
381
|
+
aa:
|
382
|
+
aab: aab (from environment)
|
383
|
+
ab:
|
384
|
+
aba: aba (from environment)
|
385
|
+
abb: abb (from environment)
|
386
|
+
mod::hash_b:
|
387
|
+
ba:
|
388
|
+
bab: bab (from environment)
|
389
|
+
bc:
|
390
|
+
bca: bca (from environment)
|
391
|
+
lookup_options:
|
392
|
+
b:
|
393
|
+
merge: hash
|
394
|
+
'^[^b]$':
|
395
|
+
merge: deep
|
396
|
+
'^c':
|
397
|
+
merge: first
|
398
|
+
'^b':
|
399
|
+
merge: first
|
400
|
+
'^mod::ha.*_b':
|
401
|
+
merge: hash
|
402
|
+
YAML
|
403
|
+
'second.yaml' => <<-YAML.unindent,
|
404
|
+
a:
|
405
|
+
aa:
|
406
|
+
aab: a.aa.aab
|
407
|
+
b:
|
408
|
+
ba:
|
409
|
+
bab: b.ba.bab
|
410
|
+
bb:
|
411
|
+
bbb: b.bb.bbb
|
412
|
+
c:
|
413
|
+
ca:
|
414
|
+
cab: c.ca.cab
|
415
|
+
YAML
|
416
|
+
},
|
417
|
+
'modules' => {
|
418
|
+
'mod' => mod_base
|
419
|
+
}
|
420
|
+
}
|
421
|
+
}
|
231
422
|
end
|
232
423
|
|
233
|
-
it '
|
234
|
-
|
235
|
-
expect(resources).to include('dflt_x')
|
424
|
+
it 'finds lookup_options that matches a pattern' do
|
425
|
+
expect(lookup('a')).to eql({'aa' => { 'aaa' => 'a.aa.aaa', 'aab' => 'a.aa.aab' }})
|
236
426
|
end
|
237
427
|
|
238
|
-
it '
|
239
|
-
|
240
|
-
expect(resources).to include('dflt_x_dflt_y')
|
428
|
+
it 'gives a direct key match higher priority than a matching pattern' do
|
429
|
+
expect(lookup('b')).to eql({'ba' => { 'baa' => 'b.ba.baa' }, 'bb' => { 'bba'=>'b.bb.bba' }})
|
241
430
|
end
|
242
431
|
|
243
|
-
it '
|
244
|
-
|
245
|
-
expect(resources).to include('dflt_x_dflt_y')
|
432
|
+
it 'uses the first matching pattern' do
|
433
|
+
expect(lookup('c')).to eql({'ca' => { 'caa' => 'c.ca.caa', 'cab' => 'c.ca.cab' }})
|
246
434
|
end
|
247
435
|
|
248
|
-
it '
|
249
|
-
expect
|
250
|
-
|
251
|
-
|
252
|
-
|
436
|
+
it 'uses lookup_option found by pattern from module' do
|
437
|
+
expect(lookup('mod::hash_a')).to eql({
|
438
|
+
'aa' => {
|
439
|
+
'aaa' => 'aaa (from module)',
|
440
|
+
'aab' => 'aab (from environment)'
|
441
|
+
},
|
442
|
+
'ab' => {
|
443
|
+
'aba' => 'aba (from environment)',
|
444
|
+
'abb' => 'abb (from environment)'
|
445
|
+
}
|
446
|
+
})
|
447
|
+
end
|
448
|
+
|
449
|
+
it 'merges lookup_options found by pattern in environment and module (environment wins)' do
|
450
|
+
expect(lookup('mod::hash_b')).to eql({
|
451
|
+
'ba' => {
|
452
|
+
'bab' => 'bab (from environment)'
|
453
|
+
},
|
454
|
+
'bb' => {
|
455
|
+
'bba' => 'bba (from module)'
|
456
|
+
},
|
457
|
+
'bc' => {
|
458
|
+
'bca' => 'bca (from environment)'
|
459
|
+
}
|
460
|
+
})
|
461
|
+
end
|
462
|
+
|
463
|
+
context 'and patterns in module are not limited to module keys' do
|
464
|
+
let(:mod_common) {
|
465
|
+
<<-YAML.unindent
|
466
|
+
mod::hash_a:
|
467
|
+
aa:
|
468
|
+
aaa: aaa (from module)
|
469
|
+
ab:
|
470
|
+
aba: aba (from module)
|
471
|
+
lookup_options:
|
472
|
+
'^.*_a':
|
473
|
+
merge: deep
|
474
|
+
YAML
|
475
|
+
}
|
476
|
+
|
477
|
+
it 'fails with error' do
|
478
|
+
expect { lookup('mod::a') }.to raise_error(Puppet::DataBinding::LookupError, /all lookup_options patterns must match a key starting with module name/)
|
479
|
+
end
|
253
480
|
end
|
254
481
|
end
|
255
482
|
|
256
|
-
context '
|
257
|
-
|
258
|
-
|
259
|
-
|
483
|
+
context 'and a global Hiera v4 configuration' do
|
484
|
+
let(:code_dir_files) do
|
485
|
+
{
|
486
|
+
'hiera.yaml' => <<-YAML.unindent,
|
487
|
+
---
|
488
|
+
version: 4
|
489
|
+
YAML
|
490
|
+
}
|
260
491
|
end
|
261
492
|
|
262
|
-
|
263
|
-
|
264
|
-
|
493
|
+
before(:each) do
|
494
|
+
# Need to set here since spec_helper defines these settings in its "before each"
|
495
|
+
Puppet.settings[:codedir] = populated_code_dir
|
496
|
+
Puppet.settings[:hiera_config] = File.join(code_dir, 'hiera.yaml')
|
265
497
|
end
|
266
498
|
|
267
|
-
it '
|
268
|
-
|
269
|
-
expect(resources).to include('dflt_x_dflt_y')
|
499
|
+
it 'raises an error' do
|
500
|
+
expect { lookup('a') }.to raise_error(Puppet::Error, /hiera configuration version 4 cannot be used in the global layer/)
|
270
501
|
end
|
502
|
+
end
|
271
503
|
|
272
|
-
|
273
|
-
|
274
|
-
|
504
|
+
context 'and an environment Hiera v3 configuration' do
|
505
|
+
let(:environment_files) do
|
506
|
+
{
|
507
|
+
env_name => {
|
508
|
+
'hiera.yaml' => <<-YAML.unindent,
|
509
|
+
---
|
510
|
+
:backends: yaml
|
511
|
+
YAML
|
512
|
+
}
|
513
|
+
}
|
275
514
|
end
|
276
515
|
|
277
|
-
it '
|
278
|
-
|
279
|
-
expect(resources).to include('no_value')
|
516
|
+
it 'raises an error' do
|
517
|
+
expect { lookup('a') }.to raise_error(Puppet::Error, /hiera configuration version 3 cannot be used in an environment/)
|
280
518
|
end
|
519
|
+
end
|
281
520
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
521
|
+
context 'and a global empty Hiera configuration' do
|
522
|
+
let(:hiera_yaml_path) { File.join(code_dir, 'hiera.yaml') }
|
523
|
+
let(:code_dir_files) do
|
524
|
+
{
|
525
|
+
'hiera.yaml' => '',
|
526
|
+
}
|
287
527
|
end
|
288
528
|
|
289
|
-
|
290
|
-
|
291
|
-
|
529
|
+
let(:environment_files) do
|
530
|
+
{
|
531
|
+
env_name => {
|
532
|
+
'hieradata' => {
|
533
|
+
'common.yaml' => <<-YAML.unindent,
|
534
|
+
x: value x (from environment)
|
535
|
+
YAML
|
536
|
+
}
|
537
|
+
}
|
538
|
+
}
|
292
539
|
end
|
293
540
|
|
294
|
-
|
295
|
-
|
296
|
-
|
541
|
+
before(:each) do
|
542
|
+
# Need to set here since spec_helper defines these settings in its "before each"
|
543
|
+
Puppet.settings[:hiera_config] = hiera_yaml_path
|
297
544
|
end
|
298
|
-
end
|
299
|
-
end
|
300
545
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
function environment::data() {
|
305
|
-
{ a => { b => { c => 'the data' }}}
|
306
|
-
}
|
307
|
-
notice(lookup('a.b.c'))
|
308
|
-
CODE
|
309
|
-
expect(eval_and_collect_notices(source)).to include('the data')
|
310
|
-
end
|
546
|
+
it 'uses a Hiera version 3 defaults' do
|
547
|
+
expect(lookup('x')).to eql('value x (from environment)')
|
548
|
+
end
|
311
549
|
|
312
|
-
|
313
|
-
|
314
|
-
function environment::data() {
|
315
|
-
{ 'a.b.c' => 'the data' }
|
316
|
-
}
|
317
|
-
notice(lookup('"a.b.c"'))
|
318
|
-
CODE
|
319
|
-
expect(eval_and_collect_notices(source)).to include('the data')
|
320
|
-
end
|
550
|
+
context 'obtained using /dev/null', :unless => Puppet.features.microsoft_windows? do
|
551
|
+
let(:code_dir_files) { {} }
|
321
552
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
notice(lookup('a."b.c"'))
|
328
|
-
CODE
|
329
|
-
expect(eval_and_collect_notices(source)).to include('the data')
|
553
|
+
it 'uses a Hiera version 3 defaults' do
|
554
|
+
Puppet[:hiera_config] = '/dev/null'
|
555
|
+
expect(lookup('x')).to eql('value x (from environment)')
|
556
|
+
end
|
557
|
+
end
|
330
558
|
end
|
331
|
-
end
|
332
559
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
560
|
+
context 'and a global configuration' do
|
561
|
+
let(:hiera_yaml) do
|
562
|
+
<<-YAML.unindent
|
563
|
+
---
|
564
|
+
:backends:
|
565
|
+
- yaml
|
566
|
+
- json
|
567
|
+
- custom
|
568
|
+
- hocon
|
569
|
+
:yaml:
|
570
|
+
:datadir: #{code_dir}/hieradata
|
571
|
+
:json:
|
572
|
+
:datadir: #{code_dir}/hieradata
|
573
|
+
:hocon:
|
574
|
+
:datadir: #{code_dir}/hieradata
|
575
|
+
:hierarchy:
|
576
|
+
- common
|
577
|
+
- "%{domain}"
|
578
|
+
:merge_behavior: deeper
|
579
|
+
YAML
|
580
|
+
end
|
338
581
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
582
|
+
let(:code_dir_files) do
|
583
|
+
{
|
584
|
+
'hiera.yaml' => hiera_yaml,
|
585
|
+
'ruby_stuff' => {
|
586
|
+
'hiera' => {
|
587
|
+
'backend' => {
|
588
|
+
'custom_backend.rb' => <<-RUBY.unindent,
|
589
|
+
class Hiera::Backend::Custom_backend
|
590
|
+
def lookup(key, scope, order_override, resolution_type, context)
|
591
|
+
case key
|
592
|
+
when 'hash_c'
|
593
|
+
{ 'hash_ca' => { 'cad' => 'value hash_c.hash_ca.cad (from global custom)' }}
|
594
|
+
when 'datasources'
|
595
|
+
Hiera::Backend.datasources(scope, order_override) { |source| source }
|
596
|
+
else
|
597
|
+
throw :no_such_key
|
598
|
+
end
|
599
|
+
end
|
600
|
+
end
|
601
|
+
RUBY
|
602
|
+
'other_backend.rb' => <<-RUBY.unindent,
|
603
|
+
class Hiera::Backend::Other_backend
|
604
|
+
def lookup(key, scope, order_override, resolution_type, context)
|
605
|
+
value = Hiera::Config[:other][key.to_sym]
|
606
|
+
throw :no_such_key if value.nil?
|
607
|
+
value
|
608
|
+
end
|
609
|
+
end
|
610
|
+
RUBY
|
611
|
+
}
|
612
|
+
}
|
613
|
+
},
|
614
|
+
'hieradata' => {
|
615
|
+
'common.yaml' => <<-YAML.unindent,
|
616
|
+
a: value a (from global)
|
617
|
+
hash_b:
|
618
|
+
hash_ba:
|
619
|
+
bab: value hash_b.hash_ba.bab (from global)
|
620
|
+
hash_c:
|
621
|
+
hash_ca:
|
622
|
+
cab: value hash_c.hash_ca.cab (from global)
|
623
|
+
YAML
|
624
|
+
'example.com.yaml' => <<-YAML.unindent,
|
625
|
+
x: value x (from global example.com.yaml)
|
626
|
+
YAML
|
627
|
+
'common.json' => <<-JSON.unindent,
|
628
|
+
{
|
629
|
+
"hash_b": {
|
630
|
+
"hash_ba": {
|
631
|
+
"bac": "value hash_b.hash_ba.bac (from global json)"
|
632
|
+
}
|
633
|
+
},
|
634
|
+
"hash_c": {
|
635
|
+
"hash_ca": {
|
636
|
+
"cac": "value hash_c.hash_ca.cac (from global json)"
|
637
|
+
}
|
638
|
+
}
|
639
|
+
}
|
640
|
+
JSON
|
641
|
+
'common.conf' => <<-HOCON.unindent,
|
642
|
+
// The 'xs' is a value used for testing
|
643
|
+
xs = { subkey = value xs.subkey (from global hocon) }
|
644
|
+
HOCON
|
645
|
+
}
|
646
|
+
}
|
647
|
+
end
|
343
648
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
649
|
+
before(:each) do
|
650
|
+
# Need to set here since spec_helper defines these settings in its "before each"
|
651
|
+
Puppet.settings[:codedir] = populated_code_dir
|
652
|
+
Puppet.settings[:hiera_config] = File.join(code_dir, 'hiera.yaml')
|
653
|
+
end
|
348
654
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
655
|
+
around(:each) do |example|
|
656
|
+
# Faking the load path to enable 'require' to load from 'ruby_stuff'. It removes the need for a static fixture
|
657
|
+
# for the custom backend
|
658
|
+
$LOAD_PATH.unshift(File.join(code_dir, 'ruby_stuff'))
|
659
|
+
begin
|
660
|
+
Puppet.override(:environments => environments, :current_environment => env) do
|
661
|
+
example.run
|
662
|
+
end
|
663
|
+
ensure
|
664
|
+
Hiera::Backend.send(:remove_const, :Custom_backend) if Hiera::Backend.const_defined?(:Custom_backend)
|
665
|
+
Hiera::Backend.send(:remove_const, :Other_backend) if Hiera::Backend.const_defined?(:Other_backend)
|
666
|
+
$LOAD_PATH.shift
|
667
|
+
end
|
668
|
+
end
|
353
669
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
670
|
+
context 'version 3' do
|
671
|
+
it 'finds data in the environment and reports deprecation warnings for both environment.conf and hiera.yaml' do
|
672
|
+
expect(lookup('a')).to eql('value a (from global)')
|
673
|
+
expect(warnings).to include(/Use of 'hiera.yaml' version 3 is deprecated. It should be converted to version 5/)
|
674
|
+
end
|
358
675
|
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
676
|
+
it 'explain contains output from global layer' do
|
677
|
+
explanation = explain('a')
|
678
|
+
expect(explanation).to include('Global Data Provider (hiera configuration version 3)')
|
679
|
+
expect(explanation).to include('Hierarchy entry "yaml"')
|
680
|
+
expect(explanation).to include('Hierarchy entry "json"')
|
681
|
+
expect(explanation).to include('Found key: "a" value: "value a (from global)"')
|
682
|
+
end
|
363
683
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
684
|
+
it 'uses the merge behavior specified in global hiera.yaml to merge only global backends' do
|
685
|
+
expect(lookup('hash_b')).to eql(
|
686
|
+
{ 'hash_ba' => { 'bab' => 'value hash_b.hash_ba.bab (from global)', 'bac' => 'value hash_b.hash_ba.bac (from global json)' } })
|
687
|
+
end
|
368
688
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
end
|
689
|
+
it 'uses the merge from lookup options to merge all layers and override merge_behavior specified in global hiera.yaml' do
|
690
|
+
expect(lookup('hash_c')).to eql(
|
691
|
+
{ 'hash_ca' => { 'cab' => 'value hash_c.hash_ca.cab (from global)' } })
|
692
|
+
end
|
374
693
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
694
|
+
it 'uses the explicitly given merge to override lookup options and to merge all layers' do
|
695
|
+
expect(lookup('hash_c', 'merge' => 'deep')).to eql(
|
696
|
+
{
|
697
|
+
'hash_ca' =>
|
698
|
+
{
|
699
|
+
'caa' => 'value hash_c.hash_ca.caa (from environment)',
|
700
|
+
'cab' => 'value hash_c.hash_ca.cab (from global)',
|
701
|
+
'cac' => 'value hash_c.hash_ca.cac (from global json)',
|
702
|
+
'cad' => 'value hash_c.hash_ca.cad (from global custom)'
|
703
|
+
}
|
704
|
+
})
|
705
|
+
end
|
380
706
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
Puppet::Util::Log.with_destination(Puppet::Test::LogCollector.new(logs)) do
|
385
|
-
Puppet[:code] = "include bad_data\nlookup('bad_data::b')"
|
386
|
-
expect { compiler.compile }.to raise_error(Puppet::ParseError, /did not find a value for the name 'bad_data::b'/)
|
387
|
-
end
|
388
|
-
warnings = logs.select {|log| log.level == :warning }.map {|log| log.message }
|
389
|
-
expect(warnings).to include("Module data for module 'bad_data' must use keys qualified with the name of the module")
|
390
|
-
end
|
707
|
+
it 'paths are interpolated' do
|
708
|
+
expect(lookup('x')).to eql('value x (from global example.com.yaml)')
|
709
|
+
end
|
391
710
|
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
Puppet::Util::Log.with_destination(Puppet::Test::LogCollector.new(logs)) do
|
396
|
-
resources = compile_and_get_notifications(<<-END.gsub(/^ {10}/, ''))
|
397
|
-
include bad_data
|
398
|
-
notify { lookup('bad_data::c'): }
|
399
|
-
END
|
400
|
-
expect(resources).to include('module_c')
|
401
|
-
end
|
402
|
-
warnings = logs.select {|log| log.level == :warning }.map {|log| log.message }
|
403
|
-
expect(warnings).to include("Module data for module 'bad_data' must use keys qualified with the name of the module")
|
404
|
-
end
|
711
|
+
it 'backend data sources are propagated to custom backend' do
|
712
|
+
expect(lookup('datasources')).to eql(['common', 'example.com'])
|
713
|
+
end
|
405
714
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
resources = compile_and_get_notifications(<<-END.gsub(/^ {8}/, '')
|
410
|
-
include bca
|
411
|
-
$r = lookup(bca::e, Hash[String,String], hash)
|
412
|
-
notify { "${r[k1]}_${r[k2]}_${r[k3]}": }
|
413
|
-
END
|
414
|
-
)
|
415
|
-
expect(resources).to include('global_e1_module_bca_e2_env_bca_e3')
|
416
|
-
end
|
715
|
+
it 'delegates configured hocon backend to hocon_data function' do
|
716
|
+
expect(explain('xs')).to match(/Hierarchy entry "hocon"\n.*\n.*\n.*"common"\n\s*Found key: "xs"/m)
|
717
|
+
end
|
417
718
|
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
resources = compile_and_get_notifications(<<-END.gsub(/^ {8}/, '')
|
422
|
-
include no_provider
|
423
|
-
$r = lookup(no_provider::e, Hash[String,String], hash)
|
424
|
-
notify { "${r[k1]}_${r[k2]}_${r[k3]}": }
|
425
|
-
END
|
426
|
-
)
|
427
|
-
expect(resources).to include('global_e1__env_no_provider_e3') # k2 is missing
|
428
|
-
end
|
429
|
-
end
|
719
|
+
it 'can dig down into subkeys provided by hocon_data function' do
|
720
|
+
expect(lookup('xs.subkey')).to eql('value xs.subkey (from global hocon)')
|
721
|
+
end
|
430
722
|
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
723
|
+
context 'using deep_merge_options supported by deep_merge gem but not supported by Puppet' do
|
724
|
+
|
725
|
+
let(:hiera_yaml) do
|
726
|
+
<<-YAML.unindent
|
727
|
+
---
|
728
|
+
:backends:
|
729
|
+
- yaml
|
730
|
+
:yaml:
|
731
|
+
:datadir: #{code_dir}/hieradata
|
732
|
+
:hierarchy:
|
733
|
+
- other
|
734
|
+
- common
|
735
|
+
:merge_behavior: deeper
|
736
|
+
:deep_merge_options:
|
737
|
+
:unpack_arrays: ','
|
738
|
+
YAML
|
739
|
+
end
|
740
|
+
|
741
|
+
let(:code_dir_files) do
|
742
|
+
{
|
743
|
+
'hiera.yaml' => hiera_yaml,
|
744
|
+
'hieradata' => {
|
745
|
+
'common.yaml' => <<-YAML.unindent,
|
746
|
+
a:
|
747
|
+
- x1,x2
|
748
|
+
YAML
|
749
|
+
'other.yaml' => <<-YAML.unindent,
|
750
|
+
a:
|
751
|
+
- x3
|
752
|
+
- x4
|
753
|
+
YAML
|
754
|
+
}
|
755
|
+
}
|
756
|
+
end
|
441
757
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
758
|
+
it 'honors option :unpack_arrays: (unsupported by puppet)' do
|
759
|
+
expect(lookup('a')).to eql(%w(x1 x2 x3 x4))
|
760
|
+
end
|
761
|
+
end
|
762
|
+
|
763
|
+
context 'using relative datadir paths' do
|
764
|
+
let(:hiera_yaml) do
|
765
|
+
<<-YAML.unindent
|
766
|
+
---
|
767
|
+
:backends:
|
768
|
+
- yaml
|
769
|
+
:yaml:
|
770
|
+
:datadir: relative_data
|
771
|
+
:hierarchy:
|
772
|
+
- common
|
773
|
+
YAML
|
774
|
+
end
|
775
|
+
|
776
|
+
let(:populated_code_dir) do
|
777
|
+
dir_contained_in(code_dir, code_dir_files.merge({
|
778
|
+
'fake_cwd' => {
|
779
|
+
'relative_data' => {
|
780
|
+
'common.yaml' => <<-YAML.unindent
|
781
|
+
a: value a (from fake_cwd/relative_data/common.yaml)
|
782
|
+
YAML
|
783
|
+
}
|
784
|
+
}
|
785
|
+
}))
|
786
|
+
code_dir
|
787
|
+
end
|
788
|
+
|
789
|
+
around(:each) do |example|
|
790
|
+
cwd = Dir.pwd
|
791
|
+
Dir.chdir(File.join(code_dir, 'fake_cwd'))
|
792
|
+
begin
|
793
|
+
example.run
|
794
|
+
ensure
|
795
|
+
Dir.chdir(cwd)
|
796
|
+
end
|
797
|
+
end
|
798
|
+
|
799
|
+
it 'finds data from data file beneath relative datadir' do
|
800
|
+
expect(lookup('a')).to eql('value a (from fake_cwd/relative_data/common.yaml)')
|
801
|
+
end
|
802
|
+
end
|
447
803
|
end
|
448
|
-
warnings = logs.select {|log| log.level == :warning }.map {|log| log.message }
|
449
|
-
expect(warnings).to include("Module data for module 'hieraprovider' must use keys qualified with the name of the module")
|
450
|
-
end
|
451
|
-
end
|
452
804
|
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
805
|
+
context 'version 5' do
|
806
|
+
let(:hiera_yaml) do
|
807
|
+
<<-YAML.unindent
|
808
|
+
---
|
809
|
+
version: 5
|
810
|
+
defaults:
|
811
|
+
datadir: hieradata
|
812
|
+
|
813
|
+
hierarchy:
|
814
|
+
- name: Yaml
|
815
|
+
data_hash: yaml_data
|
816
|
+
paths:
|
817
|
+
- common.yaml
|
818
|
+
- "%{domain}.yaml"
|
819
|
+
- name: Json
|
820
|
+
data_hash: json_data
|
821
|
+
paths:
|
822
|
+
- common.json
|
823
|
+
- "%{domain}.json"
|
824
|
+
- name: Hocon
|
825
|
+
data_hash: hocon_data
|
826
|
+
paths:
|
827
|
+
- common.conf
|
828
|
+
- "%{domain}.conf"
|
829
|
+
- name: Custom
|
830
|
+
hiera3_backend: custom
|
831
|
+
paths:
|
832
|
+
- common.custom
|
833
|
+
- "%{domain}.custom"
|
834
|
+
- name: Other
|
835
|
+
hiera3_backend: other
|
836
|
+
options:
|
837
|
+
other_option: value of other_option
|
838
|
+
paths:
|
839
|
+
- common.other
|
840
|
+
- "%{domain}.other"
|
841
|
+
YAML
|
842
|
+
end
|
459
843
|
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
end
|
465
|
-
end
|
844
|
+
it 'finds data in the environment and reports no deprecation warnings' do
|
845
|
+
expect(lookup('a')).to eql('value a (from global)')
|
846
|
+
expect(warnings).to be_empty
|
847
|
+
end
|
466
848
|
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
end
|
476
|
-
expect(lookup_invocation.explainer.to_s).to eq(<<EOS)
|
477
|
-
Merge strategy first
|
478
|
-
Data Binding "hiera"
|
479
|
-
No such key: "empty_key_yaml::has_undef_value"
|
480
|
-
Data Provider "FunctionEnvDataProvider"
|
481
|
-
No such key: "empty_key_yaml::has_undef_value"
|
482
|
-
Module "empty_key_yaml" using Data Provider "Hiera Data Provider, version 4"
|
483
|
-
ConfigurationPath "#{environmentpath}/production/modules/empty_key_yaml/hiera.yaml"
|
484
|
-
Data Provider "empty_key"
|
485
|
-
Path "#{environmentpath}/production/modules/empty_key_yaml/data/empty_key.yaml"
|
486
|
-
Original path: "empty_key"
|
487
|
-
Found key: "empty_key_yaml::has_undef_value" value: nil
|
488
|
-
Merged result: nil
|
489
|
-
EOS
|
490
|
-
end
|
491
|
-
end
|
849
|
+
it 'explain contains output from global layer' do
|
850
|
+
explanation = explain('a')
|
851
|
+
expect(explanation).to include('Global Data Provider (hiera configuration version 5)')
|
852
|
+
expect(explanation).to include('Hierarchy entry "Yaml"')
|
853
|
+
expect(explanation).to include('Hierarchy entry "Json"')
|
854
|
+
expect(explanation).to include('Hierarchy entry "Hocon"')
|
855
|
+
expect(explanation).to include('Hierarchy entry "Custom"')
|
856
|
+
expect(explanation).to include('Found key: "a" value: "value a (from global)"')
|
857
|
+
end
|
492
858
|
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
Data Provider "FunctionEnvDataProvider"
|
506
|
-
No such key: "empty_key_json::has_undef_value"
|
507
|
-
Module "empty_key_json" using Data Provider "Hiera Data Provider, version 4"
|
508
|
-
ConfigurationPath "#{environmentpath}/production/modules/empty_key_json/hiera.yaml"
|
509
|
-
Data Provider "empty_key"
|
510
|
-
Path "#{environmentpath}/production/modules/empty_key_json/data/empty_key.json"
|
511
|
-
Original path: "empty_key"
|
512
|
-
Found key: "empty_key_json::has_undef_value" value: nil
|
513
|
-
Merged result: nil
|
514
|
-
EOS
|
515
|
-
end
|
516
|
-
end
|
517
|
-
end
|
859
|
+
it 'uses the explicitly given merge to override lookup options and to merge all layers' do
|
860
|
+
expect(lookup('hash_c', 'merge' => 'deep')).to eql(
|
861
|
+
{
|
862
|
+
'hash_ca' =>
|
863
|
+
{
|
864
|
+
'caa' => 'value hash_c.hash_ca.caa (from environment)',
|
865
|
+
'cab' => 'value hash_c.hash_ca.cab (from global)',
|
866
|
+
'cac' => 'value hash_c.hash_ca.cac (from global json)',
|
867
|
+
'cad' => 'value hash_c.hash_ca.cad (from global custom)'
|
868
|
+
}
|
869
|
+
})
|
870
|
+
end
|
518
871
|
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
lookup_invocation = Puppet::Pops::Lookup::Invocation.new(scope, {}, {}, true)
|
523
|
-
begin
|
524
|
-
Puppet::Pops::Lookup.lookup('ppx::e',nil, nil, false, nil, lookup_invocation)
|
525
|
-
rescue Puppet::Error
|
526
|
-
end
|
527
|
-
expect(lookup_invocation.explainer.to_s).to eq(<<EOS)
|
528
|
-
Merge strategy first
|
529
|
-
Data Binding "hiera"
|
530
|
-
No such key: "ppx::e"
|
531
|
-
Data Provider "FunctionEnvDataProvider"
|
532
|
-
No such key: "ppx::e"
|
533
|
-
Module "ppx"
|
534
|
-
Module not found
|
535
|
-
EOS
|
536
|
-
end
|
537
|
-
end
|
872
|
+
it 'backend data sources are propagated to custom backend' do
|
873
|
+
expect(lookup('datasources')).to eql(['common', 'example.com'])
|
874
|
+
end
|
538
875
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
begin
|
543
|
-
Puppet::Pops::Lookup.lookup('abc::x', nil, nil, false, nil, lookup_invocation)
|
544
|
-
rescue Puppet::Error
|
545
|
-
end
|
546
|
-
expect(lookup_invocation.explainer.to_s).to eq(<<EOS)
|
547
|
-
Merge strategy first
|
548
|
-
Data Binding "hiera"
|
549
|
-
No such key: "abc::x"
|
550
|
-
Data Provider "FunctionEnvDataProvider"
|
551
|
-
No such key: "abc::x"
|
552
|
-
Module "abc" using Data Provider "FunctionModuleDataProvider"
|
553
|
-
No such key: "abc::x"
|
554
|
-
EOS
|
555
|
-
end
|
556
|
-
end
|
876
|
+
it 'backend specific options are propagated to custom backend' do
|
877
|
+
expect(lookup('other_option')).to eql('value of other_option')
|
878
|
+
end
|
557
879
|
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
Found key: "abc::e" value: {
|
573
|
-
"k1" => "module_e1",
|
574
|
-
"k2" => "module_e2"
|
575
|
-
}
|
576
|
-
Merged result: {
|
577
|
-
"k1" => "env_e1",
|
578
|
-
"k2" => "module_e2",
|
579
|
-
"k3" => "env_e3"
|
580
|
-
}
|
581
|
-
EOS
|
582
|
-
end
|
583
|
-
end
|
880
|
+
it 'multiple hiera3_backend declarations can be used and are merged into the generated config' do
|
881
|
+
expect(lookup(['datasources', 'other_option'])).to eql([['common', 'example.com'], 'value of other_option'])
|
882
|
+
expect(Hiera::Config.instance_variable_get(:@config)).to eql(
|
883
|
+
{
|
884
|
+
:backends => ['custom', 'other'],
|
885
|
+
:hierarchy => ['common', '%{domain}'],
|
886
|
+
:custom => { :datadir => "#{code_dir}/hieradata" },
|
887
|
+
:other => { :other_option => 'value of other_option', :datadir=>"#{code_dir}/hieradata" },
|
888
|
+
:logger => 'puppet'
|
889
|
+
})
|
890
|
+
end
|
891
|
+
|
892
|
+
it 'provides a sensible error message when the hocon library is not loaded' do
|
893
|
+
Puppet.features.stubs(:hocon?).returns(false)
|
584
894
|
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
Puppet::Pops::Lookup.lookup('abc::e', Puppet::Pops::Types::TypeParser.singleton.parse('Hash[String,String]'), nil, false, {'strategy' => 'deep', 'merge_hash_arrays' => true}, lookup_invocation)
|
590
|
-
expect(lookup_invocation.explainer.to_s).to eq(<<EOS)
|
591
|
-
Merge strategy deep
|
592
|
-
Options: {
|
593
|
-
"merge_hash_arrays" => true
|
594
|
-
}
|
595
|
-
Data Binding "hiera"
|
596
|
-
Found key: "abc::e" value: {
|
597
|
-
"k1" => "global_g1"
|
598
|
-
}
|
599
|
-
Data Provider "FunctionEnvDataProvider"
|
600
|
-
Found key: "abc::e" value: {
|
601
|
-
"k1" => "env_e1",
|
602
|
-
"k3" => "env_e3"
|
603
|
-
}
|
604
|
-
Module "abc" using Data Provider "FunctionModuleDataProvider"
|
605
|
-
Found key: "abc::e" value: {
|
606
|
-
"k1" => "module_e1",
|
607
|
-
"k2" => "module_e2"
|
608
|
-
}
|
609
|
-
Merged result: {
|
610
|
-
"k1" => "global_g1",
|
611
|
-
"k2" => "module_e2",
|
612
|
-
"k3" => "env_e3"
|
613
|
-
}
|
614
|
-
EOS
|
895
|
+
expect { lookup('a') }.to raise_error do |e|
|
896
|
+
expect(e.message).to match(/Lookup using Hocon data_hash function is not supported without hocon library/)
|
897
|
+
end
|
898
|
+
end
|
615
899
|
end
|
616
|
-
end
|
617
900
|
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
Data Provider "two paths"
|
634
|
-
Merge strategy first
|
635
|
-
Path "#{environmentpath}/production/modules/hieraprovider/data/first.json"
|
636
|
-
Original path: "first"
|
637
|
-
No such key: "hieraprovider::test::not_found"
|
638
|
-
Path "#{environmentpath}/production/modules/hieraprovider/data/second_not_present.json"
|
639
|
-
Original path: "second_not_present"
|
640
|
-
Path not found
|
641
|
-
EOS
|
901
|
+
context 'with a hiera3_backend that has no paths' do
|
902
|
+
let(:hiera_yaml) do
|
903
|
+
<<-YAML.unindent
|
904
|
+
---
|
905
|
+
version: 5
|
906
|
+
hierarchy:
|
907
|
+
- name: Custom
|
908
|
+
hiera3_backend: custom
|
909
|
+
YAML
|
910
|
+
end
|
911
|
+
|
912
|
+
it 'calls the backend' do
|
913
|
+
expect(lookup('hash_c')).to eql(
|
914
|
+
{ 'hash_ca' => { 'cad' => 'value hash_c.hash_ca.cad (from global custom)' }})
|
915
|
+
end
|
642
916
|
end
|
643
917
|
end
|
644
918
|
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
Data Binding "hiera"
|
652
|
-
No such key: "abc::f.k1.s1"
|
653
|
-
Data Provider "FunctionEnvDataProvider"
|
654
|
-
Sub key: "k1.s1"
|
655
|
-
Found key: "k1" value: {
|
656
|
-
"s1" => "env_f11",
|
657
|
-
"s2" => "env_f12"
|
658
|
-
}
|
659
|
-
Found key: "s1" value: "env_f11"
|
660
|
-
Found key: "abc::f.k1.s1" value: "env_f11"
|
661
|
-
Merged result: "env_f11"
|
662
|
-
EOS
|
919
|
+
context 'and a module' do
|
920
|
+
let(:mod_a_files) { {} }
|
921
|
+
|
922
|
+
let(:populated_env_dir) do
|
923
|
+
dir_contained_in(env_dir, DeepMerge.deep_merge!(environment_files, env_name => { 'modules' => mod_a_files }))
|
924
|
+
env_dir
|
663
925
|
end
|
664
|
-
end
|
665
926
|
|
927
|
+
context 'that has no lookup configured' do
|
928
|
+
let(:mod_a_files) do
|
929
|
+
{
|
930
|
+
'mod_a' => {
|
931
|
+
'data' => {
|
932
|
+
'common.yaml' => <<-YAML.unindent
|
933
|
+
---
|
934
|
+
mod_a::b: value mod_a::b (from mod_a)
|
935
|
+
YAML
|
936
|
+
}
|
937
|
+
}
|
938
|
+
}
|
939
|
+
end
|
940
|
+
|
941
|
+
it 'does not find data in the module' do
|
942
|
+
expect { lookup('mod_a::b') }.to raise_error(Puppet::DataBinding::LookupError, /did not find a value for the name 'mod_a::b'/)
|
943
|
+
end
|
666
944
|
|
667
|
-
|
668
|
-
|
669
|
-
lookup_invocation = Puppet::Pops::Lookup::Invocation.new(scope, {}, {}, true)
|
670
|
-
Puppet::Pops::Lookup.lookup('abc::e', Puppet::Pops::Types::TypeParser.singleton.parse('Hash[String,String]'), nil, false, {'strategy' => 'deep', 'merge_hash_arrays' => true}, lookup_invocation)
|
671
|
-
expect(lookup_invocation.explainer.to_hash).to eq(
|
945
|
+
context 'with a Hiera v3 configuration' do
|
946
|
+
let(:mod_a_files) do
|
672
947
|
{
|
673
|
-
|
948
|
+
'mod_a' => {
|
949
|
+
'hiera.yaml' => <<-YAML.unindent
|
950
|
+
---
|
951
|
+
:backends: yaml
|
952
|
+
YAML
|
953
|
+
}
|
954
|
+
}
|
955
|
+
end
|
956
|
+
|
957
|
+
it 'raises an error' do
|
958
|
+
expect { lookup('mod_a::a') }.to raise_error(Puppet::Error, /hiera configuration version 3 cannot be used in a module/)
|
959
|
+
end
|
960
|
+
end
|
961
|
+
|
962
|
+
context "but a metadata.json with 'module_data_provider=hiera'" do
|
963
|
+
let(:mod_a_files_1) { DeepMerge.deep_merge!(mod_a_files, 'mod_a' => { 'metadata.json' => <<-JSON.unindent }) }
|
674
964
|
{
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
965
|
+
"name": "example/mod_a",
|
966
|
+
"version": "0.0.2",
|
967
|
+
"source": "git@github.com/example/mod_a.git",
|
968
|
+
"dependencies": [],
|
969
|
+
"author": "Bob the Builder",
|
970
|
+
"license": "Apache-2.0",
|
971
|
+
"data_provider": "hiera"
|
972
|
+
}
|
973
|
+
JSON
|
974
|
+
|
975
|
+
let(:populated_env_dir) do
|
976
|
+
dir_contained_in(env_dir, DeepMerge.deep_merge!(environment_files, env_name => { 'modules' => mod_a_files_1 }))
|
977
|
+
env_dir
|
978
|
+
end
|
979
|
+
|
980
|
+
it 'finds data in the module and reports deprecation warning for metadata.json' do
|
981
|
+
expect(lookup('mod_a::b')).to eql('value mod_a::b (from mod_a)')
|
982
|
+
expect(warnings).to include(/Defining "data_provider": "hiera" in metadata.json is deprecated. A 'hiera.yaml' file should be used instead/)
|
983
|
+
end
|
984
|
+
|
985
|
+
context 'and a hiera.yaml file' do
|
986
|
+
let(:mod_a_files_2) { DeepMerge.deep_merge!(mod_a_files_1, 'mod_a' => { 'hiera.yaml' => <<-YAML.unindent }) }
|
987
|
+
---
|
988
|
+
version: 4
|
989
|
+
hierarchy:
|
990
|
+
- name: common
|
991
|
+
backend: yaml
|
992
|
+
YAML
|
993
|
+
|
994
|
+
let(:populated_env_dir) do
|
995
|
+
dir_contained_in(env_dir, DeepMerge.deep_merge!(environment_files, env_name => { 'modules' => mod_a_files_2 }))
|
996
|
+
env_dir
|
997
|
+
end
|
998
|
+
|
999
|
+
it 'finds data in the module and reports deprecation warnings for both metadata.json and hiera.yaml' do
|
1000
|
+
expect(lookup('mod_a::b')).to eql('value mod_a::b (from mod_a)')
|
1001
|
+
expect(warnings).to include(/Defining "data_provider": "hiera" in metadata.json is deprecated/)
|
1002
|
+
expect(warnings).to include(/Use of 'hiera.yaml' version 4 is deprecated. It should be converted to version 5/)
|
1003
|
+
end
|
1004
|
+
end
|
1005
|
+
end
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
context 'using a data_hash that reads a yaml file' do
|
1009
|
+
let(:mod_a_files) do
|
1010
|
+
{
|
1011
|
+
'mod_a' => {
|
1012
|
+
'data' => {
|
1013
|
+
'common.yaml' => <<-YAML.unindent
|
1014
|
+
---
|
1015
|
+
mod_a::a: value mod_a::a (from mod_a)
|
1016
|
+
mod_a::b: value mod_a::b (from mod_a)
|
1017
|
+
mod_a::xo: value mod_a::xo (from mod_a)
|
1018
|
+
mod_a::xd_found: value mod_a::xd_found (from mod_a)
|
1019
|
+
mod_a::interpolate_xo: "-- %{lookup('mod_a::xo')} --"
|
1020
|
+
mod_a::interpolate_xd: "-- %{lookup('mod_a::xd')} --"
|
1021
|
+
mod_a::interpolate_scope_xo: "-- %{scope_xo} --"
|
1022
|
+
mod_a::interpolate_scope_xd: "-- %{scope_xd} --"
|
1023
|
+
mod_a::hash_a:
|
1024
|
+
a: value mod_a::hash_a.a (from mod_a)
|
1025
|
+
b: value mod_a::hash_a.b (from mod_a)
|
1026
|
+
mod_a::hash_b:
|
1027
|
+
a: value mod_a::hash_b.a (from mod_a)
|
1028
|
+
b: value mod_a::hash_b.b (from mod_a)
|
1029
|
+
mod_a::interpolated: "-- %{lookup('mod_a::a')} --"
|
1030
|
+
mod_a::a_a: "-- %{lookup('mod_a::hash_a.a')} --"
|
1031
|
+
mod_a::a_b: "-- %{lookup('mod_a::hash_a.b')} --"
|
1032
|
+
mod_a::b_a: "-- %{lookup('mod_a::hash_b.a')} --"
|
1033
|
+
mod_a::b_b: "-- %{lookup('mod_a::hash_b.b')} --"
|
1034
|
+
mod_a::interpolate_array:
|
1035
|
+
- "-- %{lookup('mod_a::a')} --"
|
1036
|
+
- "-- %{lookup('mod_a::b')} --"
|
1037
|
+
mod_a::interpolate_literal: "-- %{literal('hello')} --"
|
1038
|
+
mod_a::interpolate_scope: "-- %{scope_scalar} --"
|
1039
|
+
mod_a::interpolate_scope_not_found: "-- %{scope_nope} --"
|
1040
|
+
mod_a::interpolate_scope_dig: "-- %{scope_hash.a} --"
|
1041
|
+
mod_a::interpolate_scope_dig_not_found: "-- %{scope_hash.nope} --"
|
1042
|
+
mod_a::quoted_interpolation: '-- %{lookup(''"mod_a::a.quoted.key"'')} --'
|
1043
|
+
"mod_a::a.quoted.key": "value mod_a::a.quoted.key (from mod_a)"
|
1044
|
+
YAML
|
679
1045
|
},
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
:
|
685
|
-
|
1046
|
+
'hiera.yaml' => <<-YAML.unindent,
|
1047
|
+
---
|
1048
|
+
version: 5
|
1049
|
+
hierarchy:
|
1050
|
+
- name: "Common"
|
1051
|
+
data_hash: yaml_data
|
1052
|
+
path: "common.yaml"
|
1053
|
+
YAML
|
1054
|
+
}
|
1055
|
+
}
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
it 'finds data in the module' do
|
1059
|
+
expect(lookup('mod_a::b')).to eql('value mod_a::b (from mod_a)')
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
it 'environment data has higher priority than module data' do
|
1063
|
+
expect(lookup('mod_a::a')).to eql('value mod_a::a (from environment)')
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
it 'environment data has higher priority than module data in interpolated module data' do
|
1067
|
+
expect(lookup('mod_a::interpolated')).to eql('-- value mod_a::a (from environment) --')
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
it 'overrides have higher priority than found data' do
|
1071
|
+
expect(lookup('mod_a::xo', { 'override' => overrides })).to eql('value mod_a::xo (from override)')
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
it 'overrides have higher priority than found data in lookup interpolations' do
|
1075
|
+
expect(lookup('mod_a::interpolate_xo', { 'override' => overrides })).to eql('-- value mod_a::xo (from override) --')
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
it 'overrides have higher priority than found data in scope interpolations' do
|
1079
|
+
expect(lookup('mod_a::interpolate_scope_xo', { 'override' => overrides })).to eql('-- value scope_xo (from override) --')
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
it 'defaults have lower priority than found data' do
|
1083
|
+
expect(lookup('mod_a::xd_found', { 'default_values_hash' => defaults })).to eql('value mod_a::xd_found (from mod_a)')
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
it 'defaults are used when data is not found' do
|
1087
|
+
expect(lookup('mod_a::xd', { 'default_values_hash' => defaults })).to eql('value mod_a::xd (from default)')
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
it 'defaults are used when data is not found in lookup interpolations' do
|
1091
|
+
expect(lookup('mod_a::interpolate_xd', { 'default_values_hash' => defaults })).to eql('-- value mod_a::xd (from default) --')
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
it 'defaults are used when data is not found in scope interpolations' do
|
1095
|
+
expect(lookup('mod_a::interpolate_scope_xd', { 'default_values_hash' => defaults })).to eql('-- value scope_xd (from default) --')
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
it 'merges hashes from environment and module unless strategy hash is used' do
|
1099
|
+
expect(lookup('mod_a::hash_a')).to eql({'a' => 'value mod_a::hash_a.a (from environment)'})
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
it 'merges hashes from environment and module when merge strategy hash is used' do
|
1103
|
+
expect(lookup('mod_a::hash_a', :merge => 'hash')).to eql(
|
1104
|
+
{'a' => 'value mod_a::hash_a.a (from environment)', 'b' => 'value mod_a::hash_a.b (from mod_a)'})
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
it 'will not merge hashes from environment and module in interpolated expressions' do
|
1108
|
+
expect(lookup(['mod_a::a_a', 'mod_a::a_b'])).to eql(
|
1109
|
+
['-- value mod_a::hash_a.a (from environment) --', '-- --']) # root key found in environment, no hash merge is performed
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
it 'interpolates arrays' do
|
1113
|
+
expect(lookup('mod_a::interpolate_array')).to eql(['-- value mod_a::a (from environment) --', '-- value mod_a::b (from mod_a) --'])
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
it 'can dig into arrays using subkeys' do
|
1117
|
+
expect(lookup('mod_a::interpolate_array.1')).to eql('-- value mod_a::b (from mod_a) --')
|
1118
|
+
end
|
1119
|
+
|
1120
|
+
it 'treats an out of range subkey as not found' do
|
1121
|
+
expect(explain('mod_a::interpolate_array.2')).to match(/No such key: "2"/)
|
1122
|
+
end
|
1123
|
+
|
1124
|
+
it 'interpolates a literal' do
|
1125
|
+
expect(lookup('mod_a::interpolate_literal')).to eql('-- hello --')
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
it 'interpolates scalar from scope' do
|
1129
|
+
expect(lookup('mod_a::interpolate_scope')).to eql('-- scope scalar value --')
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
it 'interpolates not found in scope as empty string' do
|
1133
|
+
expect(lookup('mod_a::interpolate_scope_not_found')).to eql('-- --')
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
it 'interpolates dotted key from scope' do
|
1137
|
+
expect(lookup('mod_a::interpolate_scope_dig')).to eql('-- scope hash a --')
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
it 'treates interpolated dotted key but not found in scope as empty string' do
|
1141
|
+
expect(lookup('mod_a::interpolate_scope_dig_not_found')).to eql('-- --')
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
it 'can use quoted keys in interpolation' do
|
1145
|
+
expect(lookup('mod_a::quoted_interpolation')).to eql('-- value mod_a::a.quoted.key (from mod_a) --') # root key found in environment, no hash merge is performed
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
it 'merges hashes from environment and module in interpolated expressions if hash merge is specified in lookup options' do
|
1149
|
+
expect(lookup(['mod_a::b_a', 'mod_a::b_b'])).to eql(
|
1150
|
+
['-- value mod_a::hash_b.a (from environment) --', '-- value mod_a::hash_b.b (from mod_a) --'])
|
1151
|
+
end
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
context 'using a lookup_key that uses a path' do
|
1155
|
+
let(:mod_a_files) do
|
1156
|
+
{
|
1157
|
+
'mod_a' => {
|
1158
|
+
'functions' => {
|
1159
|
+
'pp_lookup_key.pp' => <<-PUPPET.unindent
|
1160
|
+
function mod_a::pp_lookup_key($key, $options, $context) {
|
1161
|
+
if !$context.cache_has_key(undef) {
|
1162
|
+
$context.cache_all(yaml_data($options, $context))
|
1163
|
+
$context.cache(undef, true)
|
1164
|
+
}
|
1165
|
+
if $context.cache_has_key($key) { $context.cached_value($key) } else { $context.not_found }
|
1166
|
+
}
|
1167
|
+
PUPPET
|
686
1168
|
},
|
687
|
-
|
688
|
-
|
689
|
-
:
|
690
|
-
:
|
691
|
-
|
692
|
-
|
693
|
-
|
1169
|
+
'hiera.yaml' => <<-YAML.unindent,
|
1170
|
+
---
|
1171
|
+
version: 5
|
1172
|
+
hierarchy:
|
1173
|
+
- name: "Common"
|
1174
|
+
lookup_key: mod_a::pp_lookup_key
|
1175
|
+
path: common.yaml
|
1176
|
+
YAML
|
1177
|
+
'data' => {
|
1178
|
+
'common.yaml' => <<-YAML.unindent
|
1179
|
+
mod_a::b: value mod_a::b (from mod_a)
|
1180
|
+
YAML
|
694
1181
|
}
|
695
|
-
],
|
696
|
-
:value => { 'k1' => 'env_e1', 'k2' => 'module_e2', 'k3' => 'env_e3' },
|
697
|
-
:event => :result,
|
698
|
-
:merge => :deep,
|
699
|
-
:options => { 'merge_hash_arrays' => true },
|
700
|
-
:type => :merge
|
701
1182
|
}
|
702
|
-
|
1183
|
+
}
|
1184
|
+
end
|
1185
|
+
|
1186
|
+
it 'finds data in the module' do
|
1187
|
+
expect(lookup('mod_a::b')).to eql('value mod_a::b (from mod_a)')
|
1188
|
+
end
|
703
1189
|
end
|
704
|
-
end
|
705
1190
|
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
1191
|
+
context 'using a lookup_key that is a puppet function' do
|
1192
|
+
let(:mod_a_files) do
|
1193
|
+
{
|
1194
|
+
'mod_a' => {
|
1195
|
+
'functions' => {
|
1196
|
+
'pp_lookup_key.pp' => <<-PUPPET.unindent
|
1197
|
+
function mod_a::pp_lookup_key($key, $options, $context) {
|
1198
|
+
case $key {
|
1199
|
+
'mod_a::really_interpolated': { $context.interpolate("-- %{lookup('mod_a::a')} --") }
|
1200
|
+
'mod_a::recursive': { lookup($key) }
|
1201
|
+
default: {
|
1202
|
+
if $context.cache_has_key(mod_a::a) {
|
1203
|
+
$context.explain || { 'reusing cache' }
|
1204
|
+
} else {
|
1205
|
+
$context.explain || { 'initializing cache' }
|
1206
|
+
$context.cache_all({
|
1207
|
+
mod_a::a => 'value mod_a::a (from mod_a)',
|
1208
|
+
mod_a::b => 'value mod_a::b (from mod_a)',
|
1209
|
+
mod_a::c => 'value mod_a::c (from mod_a)',
|
1210
|
+
mod_a::hash_a => {
|
1211
|
+
a => 'value mod_a::hash_a.a (from mod_a)',
|
1212
|
+
b => 'value mod_a::hash_a.b (from mod_a)'
|
1213
|
+
},
|
1214
|
+
mod_a::hash_b => {
|
1215
|
+
a => 'value mod_a::hash_b.a (from mod_a)',
|
1216
|
+
b => 'value mod_a::hash_b.b (from mod_a)'
|
1217
|
+
},
|
1218
|
+
mod_a::interpolated => "-- %{lookup('mod_a::a')} --",
|
1219
|
+
mod_a::a_a => "-- %{lookup('mod_a::hash_a.a')} --",
|
1220
|
+
mod_a::a_b => "-- %{lookup('mod_a::hash_a.b')} --",
|
1221
|
+
mod_a::b_a => "-- %{lookup('mod_a::hash_b.a')} --",
|
1222
|
+
mod_a::b_b => "-- %{lookup('mod_a::hash_b.b')} --",
|
1223
|
+
'mod_a::a.quoted.key' => 'value mod_a::a.quoted.key (from mod_a)',
|
1224
|
+
mod_a::sensitive => Sensitive('reduct me please'),
|
1225
|
+
mod_a::type => Object[{name => 'FindMe', 'attributes' => {'x' => String}}],
|
1226
|
+
mod_a::version => SemVer('3.4.1'),
|
1227
|
+
mod_a::version_range => SemVerRange('>=3.4.1'),
|
1228
|
+
mod_a::timestamp => Timestamp("1994-03-25T19:30:00"),
|
1229
|
+
mod_a::timespan => Timespan("3-10:00:00")
|
1230
|
+
})
|
1231
|
+
}
|
1232
|
+
if !$context.cache_has_key($key) {
|
1233
|
+
$context.not_found
|
1234
|
+
}
|
1235
|
+
$context.explain || { "returning value for $key" }
|
1236
|
+
$context.cached_value($key)
|
1237
|
+
}
|
1238
|
+
}
|
1239
|
+
}
|
1240
|
+
PUPPET
|
1241
|
+
},
|
1242
|
+
'hiera.yaml' => <<-YAML.unindent,
|
1243
|
+
---
|
1244
|
+
version: 5
|
1245
|
+
hierarchy:
|
1246
|
+
- name: "Common"
|
1247
|
+
lookup_key: mod_a::pp_lookup_key
|
1248
|
+
YAML
|
1249
|
+
}
|
1250
|
+
}
|
1251
|
+
end
|
1252
|
+
|
1253
|
+
it 'finds data in the module' do
|
1254
|
+
expect(lookup('mod_a::b')).to eql('value mod_a::b (from mod_a)')
|
1255
|
+
end
|
1256
|
+
|
1257
|
+
it 'environment data has higher priority than module data' do
|
1258
|
+
expect(lookup('mod_a::a')).to eql('value mod_a::a (from environment)')
|
1259
|
+
end
|
1260
|
+
|
1261
|
+
it 'finds quoted keys in the module' do
|
1262
|
+
expect(lookup('"mod_a::a.quoted.key"')).to eql('value mod_a::a.quoted.key (from mod_a)')
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
it 'will not resolve interpolated expressions' do
|
1266
|
+
expect(lookup('mod_a::interpolated')).to eql("-- %{lookup('mod_a::a')} --")
|
1267
|
+
end
|
1268
|
+
|
1269
|
+
it 'resolves interpolated expressions using Context#interpolate' do
|
1270
|
+
expect(lookup('mod_a::really_interpolated')).to eql("-- value mod_a::a (from environment) --")
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
it 'will not merge hashes from environment and module unless strategy hash is used' do
|
1274
|
+
expect(lookup('mod_a::hash_a')).to eql({ 'a' => 'value mod_a::hash_a.a (from environment)' })
|
1275
|
+
end
|
1276
|
+
|
1277
|
+
it 'merges hashes from environment and module when merge strategy hash is used' do
|
1278
|
+
expect(lookup('mod_a::hash_a', :merge => 'hash')).to eql({ 'a' => 'value mod_a::hash_a.a (from environment)', 'b' => 'value mod_a::hash_a.b (from mod_a)' })
|
1279
|
+
end
|
1280
|
+
|
1281
|
+
it 'traps recursive lookup trapped' do
|
1282
|
+
expect(explain('mod_a::recursive')).to include('Recursive lookup detected')
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
it 'private cache is persisted over multiple calls' do
|
1286
|
+
collect_notices("notice(lookup('mod_a::b')) notice(lookup('mod_a::c'))", true)
|
1287
|
+
expect(notices).to eql(['value mod_a::b (from mod_a)', 'value mod_a::c (from mod_a)'])
|
1288
|
+
expect(explanation).to match(/initializing cache.*reusing cache/m)
|
1289
|
+
expect(explanation).not_to match(/initializing cache.*initializing cache/m)
|
1290
|
+
end
|
1291
|
+
|
1292
|
+
it 'the same key is requested only once' do
|
1293
|
+
collect_notices("notice(lookup('mod_a::b')) notice(lookup('mod_a::b'))", true)
|
1294
|
+
expect(notices).to eql(['value mod_a::b (from mod_a)', 'value mod_a::b (from mod_a)'])
|
1295
|
+
expect(explanation).to match(/Found key: "mod_a::b".*Found key: "mod_a::b"/m)
|
1296
|
+
expect(explanation).to match(/returning value for mod_a::b/m)
|
1297
|
+
expect(explanation).not_to match(/returning value for mod_a::b.*returning value for mod_a::b/m)
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
context 'and calling function via API' do
|
1301
|
+
it 'finds and delivers rich data' do
|
1302
|
+
collect_notices("notice('success')") do |scope|
|
1303
|
+
expect(lookup_func.call(scope, 'mod_a::sensitive')).to be_a(Puppet::Pops::Types::PSensitiveType::Sensitive)
|
1304
|
+
expect(lookup_func.call(scope, 'mod_a::type')).to be_a(Puppet::Pops::Types::PObjectType)
|
1305
|
+
expect(lookup_func.call(scope, 'mod_a::version')).to eql(SemanticPuppet::Version.parse('3.4.1'))
|
1306
|
+
expect(lookup_func.call(scope, 'mod_a::version_range')).to eql(SemanticPuppet::VersionRange.parse('>=3.4.1'))
|
1307
|
+
expect(lookup_func.call(scope, 'mod_a::timestamp')).to eql(Puppet::Pops::Time::Timestamp.parse('1994-03-25T19:30:00'))
|
1308
|
+
expect(lookup_func.call(scope, 'mod_a::timespan')).to eql(Puppet::Pops::Time::Timespan.parse('3-10:00:00'))
|
1309
|
+
end
|
1310
|
+
expect(notices).to eql(['success'])
|
1311
|
+
end
|
712
1312
|
end
|
713
|
-
expect(lookup_invocation.explainer.to_s).to eq(<<EOS)
|
714
|
-
Invalid key "lookup_options"
|
715
|
-
EOS
|
716
1313
|
end
|
717
|
-
end
|
718
1314
|
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
1315
|
+
context 'using a data_dig that is a ruby function' do
|
1316
|
+
let(:mod_a_files) do
|
1317
|
+
{
|
1318
|
+
'mod_a' => {
|
1319
|
+
'lib' => {
|
1320
|
+
'puppet' => {
|
1321
|
+
'functions' => {
|
1322
|
+
'mod_a' => {
|
1323
|
+
'ruby_dig.rb' => <<-RUBY.unindent
|
1324
|
+
Puppet::Functions.create_function(:'mod_a::ruby_dig') do
|
1325
|
+
dispatch :ruby_dig do
|
1326
|
+
param 'Array[String[1]]', :segments
|
1327
|
+
param 'Hash[String,Any]', :options
|
1328
|
+
param 'Puppet::LookupContext', :context
|
1329
|
+
end
|
1330
|
+
|
1331
|
+
def ruby_dig(segments, options, context)
|
1332
|
+
sub_segments = segments.dup
|
1333
|
+
root_key = sub_segments.shift
|
1334
|
+
case root_key
|
1335
|
+
when 'mod_a::options'
|
1336
|
+
hash = { 'mod_a::options' => options }
|
1337
|
+
when 'mod_a::lookup'
|
1338
|
+
return call_function('lookup', segments.join('.'))
|
1339
|
+
else
|
1340
|
+
hash = {
|
1341
|
+
'mod_a::a' => 'value mod_a::a (from mod_a)',
|
1342
|
+
'mod_a::b' => 'value mod_a::b (from mod_a)',
|
1343
|
+
'mod_a::hash_a' => {
|
1344
|
+
'a' => 'value mod_a::hash_a.a (from mod_a)',
|
1345
|
+
'b' => 'value mod_a::hash_a.b (from mod_a)'
|
1346
|
+
},
|
1347
|
+
'mod_a::hash_b' => {
|
1348
|
+
'a' => 'value mod_a::hash_b.a (from mod_a)',
|
1349
|
+
'b' => 'value mod_a::hash_b.b (from mod_a)'
|
1350
|
+
},
|
1351
|
+
'mod_a::interpolated' => "-- %{lookup('mod_a::a')} --",
|
1352
|
+
'mod_a::really_interpolated' => "-- %{lookup('mod_a::a')} --",
|
1353
|
+
'mod_a::a_a' => "-- %{lookup('mod_a::hash_a.a')} --",
|
1354
|
+
'mod_a::a_b' => "-- %{lookup('mod_a::hash_a.b')} --",
|
1355
|
+
'mod_a::b_a' => "-- %{lookup('mod_a::hash_b.a')} --",
|
1356
|
+
'mod_a::b_b' => "-- %{lookup('mod_a::hash_b.b')} --",
|
1357
|
+
'mod_a::bad_type' => :oops,
|
1358
|
+
'mod_a::bad_type_in_hash' => { 'a' => :oops },
|
1359
|
+
}
|
1360
|
+
end
|
1361
|
+
context.not_found unless hash.include?(root_key)
|
1362
|
+
value = sub_segments.reduce(hash[root_key]) do |memo, segment|
|
1363
|
+
context.not_found unless memo.is_a?(Hash) && memo.include?(segment)
|
1364
|
+
memo[segment]
|
1365
|
+
end
|
1366
|
+
root_key == 'mod_a::really_interpolated' ? context.interpolate(value) : value
|
1367
|
+
end
|
1368
|
+
end
|
1369
|
+
RUBY
|
1370
|
+
}
|
1371
|
+
}
|
1372
|
+
}
|
1373
|
+
},
|
1374
|
+
'hiera.yaml' => <<-YAML.unindent,
|
1375
|
+
---
|
1376
|
+
version: 5
|
1377
|
+
hierarchy:
|
1378
|
+
- name: "Common"
|
1379
|
+
data_dig: mod_a::ruby_dig
|
1380
|
+
uri: "http://www.example.com/passed/as/option"
|
1381
|
+
options:
|
1382
|
+
option_a: Option value a
|
1383
|
+
option_b:
|
1384
|
+
x: Option value b.x
|
1385
|
+
y: Option value b.y
|
1386
|
+
YAML
|
1387
|
+
}
|
1388
|
+
}
|
1389
|
+
end
|
1390
|
+
|
1391
|
+
it 'finds data in the module' do
|
1392
|
+
expect(lookup('mod_a::b')).to eql('value mod_a::b (from mod_a)')
|
1393
|
+
end
|
1394
|
+
|
1395
|
+
it 'environment data has higher priority than module data' do
|
1396
|
+
expect(lookup('mod_a::a')).to eql('value mod_a::a (from environment)')
|
1397
|
+
end
|
1398
|
+
|
1399
|
+
it 'will not resolve interpolated expressions' do
|
1400
|
+
expect(lookup('mod_a::interpolated')).to eql("-- %{lookup('mod_a::a')} --")
|
1401
|
+
end
|
1402
|
+
|
1403
|
+
it 'resolves interpolated expressions using Context#interpolate' do
|
1404
|
+
expect(lookup('mod_a::really_interpolated')).to eql("-- value mod_a::a (from environment) --")
|
1405
|
+
end
|
1406
|
+
|
1407
|
+
it 'does not accept return of runtime type from function' do
|
1408
|
+
expect(explain('mod_a::bad_type')).to include('Value returned from Hierarchy entry "Common" has wrong type')
|
1409
|
+
end
|
1410
|
+
|
1411
|
+
it 'does not accept return of runtime type embedded in hash from function' do
|
1412
|
+
expect(explain('mod_a::bad_type_in_hash')).to include('Value returned from Hierarchy entry "Common" has wrong type')
|
1413
|
+
end
|
1414
|
+
|
1415
|
+
it 'will not merge hashes from environment and module unless strategy hash is used' do
|
1416
|
+
expect(lookup('mod_a::hash_a')).to eql({'a' => 'value mod_a::hash_a.a (from environment)'})
|
1417
|
+
end
|
1418
|
+
|
1419
|
+
it 'hierarchy entry options are passed to the function' do
|
1420
|
+
expect(lookup('mod_a::options.option_b.x')).to eql('Option value b.x')
|
1421
|
+
end
|
1422
|
+
|
1423
|
+
it 'hierarchy entry "uri" is passed as location option to the function' do
|
1424
|
+
expect(lookup('mod_a::options.uri')).to eql('http://www.example.com/passed/as/option')
|
1425
|
+
end
|
1426
|
+
|
1427
|
+
it 'recursive lookup is trapped' do
|
1428
|
+
expect(explain('mod_a::lookup.mod_a::lookup')).to include('Recursive lookup detected')
|
1429
|
+
end
|
1430
|
+
|
1431
|
+
context 'with merge strategy hash' do
|
1432
|
+
it 'merges hashes from environment and module' do
|
1433
|
+
expect(lookup('mod_a::hash_a', :merge => 'hash')).to eql({'a' => 'value mod_a::hash_a.a (from environment)', 'b' => 'value mod_a::hash_a.b (from mod_a)'})
|
1434
|
+
end
|
1435
|
+
|
1436
|
+
it 'will "undig" value from data_dig function, merge root hashes, and then dig to get values by subkey' do
|
1437
|
+
expect(lookup(['mod_a::hash_a.a', 'mod_a::hash_a.b'], :merge => 'hash')).to eql(
|
1438
|
+
['value mod_a::hash_a.a (from environment)', 'value mod_a::hash_a.b (from mod_a)'])
|
1439
|
+
end
|
725
1440
|
end
|
726
|
-
expect(lookup_invocation.explainer.to_s).to eq(<<EOS)
|
727
|
-
Invalid key "lookup_options"
|
728
|
-
EOS
|
729
1441
|
end
|
730
1442
|
end
|
731
|
-
|
732
1443
|
end
|
733
1444
|
end
|