puppet 6.10.1-universal-darwin → 6.11.0-universal-darwin
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 +4 -4
- data/Gemfile +4 -4
- data/Gemfile.lock +20 -12
- data/ext/project_data.yaml +3 -2
- data/ext/regexp_nodes/regexp_nodes.rb +4 -4
- data/ext/windows/service/daemon.rb +33 -8
- data/install.rb +6 -6
- data/lib/puppet.rb +8 -0
- data/lib/puppet/application.rb +1 -1
- data/lib/puppet/application/agent.rb +3 -0
- data/lib/puppet/application/apply.rb +2 -2
- data/lib/puppet/application/describe.rb +3 -9
- data/lib/puppet/application/device.rb +3 -0
- data/lib/puppet/application/doc.rb +1 -1
- data/lib/puppet/application/lookup.rb +1 -1
- data/lib/puppet/application/script.rb +2 -2
- data/lib/puppet/application/ssl.rb +25 -21
- data/lib/puppet/configurer.rb +42 -0
- data/lib/puppet/configurer/downloader.rb +2 -6
- data/lib/puppet/context/trusted_information.rb +42 -4
- data/lib/puppet/defaults.rb +19 -4
- data/lib/puppet/face/module/list.rb +5 -5
- data/lib/puppet/face/module/search.rb +1 -1
- data/lib/puppet/face/module/uninstall.rb +1 -1
- data/lib/puppet/face/module/upgrade.rb +1 -1
- data/lib/puppet/file_serving/http_metadata.rb +1 -1
- data/lib/puppet/file_system.rb +0 -8
- data/lib/puppet/file_system/memory_file.rb +1 -1
- data/lib/puppet/file_system/posix.rb +3 -2
- data/lib/puppet/forge.rb +3 -3
- data/lib/puppet/functions.rb +1 -2
- data/lib/puppet/gettext/module_translations.rb +1 -1
- data/lib/puppet/graph/rb_tree_map.rb +2 -2
- data/lib/puppet/graph/simple_graph.rb +4 -3
- data/lib/puppet/http.rb +29 -0
- data/lib/puppet/http/client.rb +156 -0
- data/lib/puppet/http/errors.rb +30 -0
- data/lib/puppet/http/redirector.rb +48 -0
- data/lib/puppet/http/resolver.rb +5 -0
- data/lib/puppet/http/resolver/settings.rb +5 -0
- data/lib/puppet/http/resolver/srv.rb +13 -0
- data/lib/puppet/http/response.rb +34 -0
- data/lib/puppet/http/retry_after_handler.rb +47 -0
- data/lib/puppet/http/service.rb +18 -0
- data/lib/puppet/http/service/ca.rb +49 -0
- data/lib/puppet/http/session.rb +55 -0
- data/lib/puppet/indirector/file_bucket_file/file.rb +1 -1
- data/lib/puppet/indirector/hiera.rb +2 -0
- data/lib/puppet/indirector/request.rb +1 -1
- data/lib/puppet/indirector/resource/ral.rb +1 -3
- data/lib/puppet/indirector/resource/validator.rb +1 -1
- data/lib/puppet/interface.rb +2 -1
- data/lib/puppet/interface/documentation.rb +1 -1
- data/lib/puppet/loaders.rb +0 -1
- data/lib/puppet/metatype/manager.rb +1 -1
- data/lib/puppet/module.rb +1 -1
- data/lib/puppet/module/task.rb +20 -4
- data/lib/puppet/module_tool/applications/installer.rb +1 -1
- data/lib/puppet/module_tool/applications/uninstaller.rb +3 -3
- data/lib/puppet/module_tool/metadata.rb +1 -1
- data/lib/puppet/module_tool/shared_behaviors.rb +4 -4
- data/lib/puppet/module_tool/tar/mini.rb +1 -1
- data/lib/puppet/network/http.rb +2 -6
- data/lib/puppet/network/http/api/indirected_routes.rb +12 -11
- data/lib/puppet/network/http/connection.rb +10 -12
- data/lib/puppet/network/http/pool.rb +2 -0
- data/lib/puppet/network/http/site.rb +5 -1
- data/lib/puppet/network/resolver.rb +4 -4
- data/lib/puppet/node/environment.rb +4 -2
- data/lib/puppet/pal/pal_impl.rb +2 -2
- data/lib/puppet/parser/ast.rb +1 -1
- data/lib/puppet/parser/ast/resourceparam.rb +1 -1
- data/lib/puppet/parser/functions.rb +1 -1
- data/lib/puppet/parser/scope.rb +8 -7
- data/lib/puppet/pops/evaluator/collectors/catalog_collector.rb +1 -1
- data/lib/puppet/pops/evaluator/collectors/exported_collector.rb +1 -1
- data/lib/puppet/pops/evaluator/external_syntax_support.rb +3 -2
- data/lib/puppet/pops/evaluator/runtime3_support.rb +4 -7
- data/lib/puppet/pops/loader/module_loaders.rb +1 -1
- data/lib/puppet/pops/loader/task_instantiator.rb +4 -0
- data/lib/puppet/pops/loaders.rb +1 -1
- data/lib/puppet/pops/lookup/hiera_config.rb +1 -0
- data/lib/puppet/pops/lookup/sub_lookup.rb +1 -1
- data/lib/puppet/pops/merge_strategy.rb +22 -18
- data/lib/puppet/pops/parser/heredoc_support.rb +1 -1
- data/lib/puppet/pops/parser/interpolation_support.rb +4 -4
- data/lib/puppet/pops/parser/locator.rb +1 -1
- data/lib/puppet/pops/parser/pn_parser.rb +17 -16
- data/lib/puppet/pops/puppet_stack.rb +52 -48
- data/lib/puppet/pops/types/p_sensitive_type.rb +1 -1
- data/lib/puppet/pops/types/p_uri_type.rb +1 -1
- data/lib/puppet/pops/types/string_converter.rb +10 -10
- data/lib/puppet/pops/types/types.rb +3 -3
- data/lib/puppet/property.rb +1 -1
- data/lib/puppet/property/ensure.rb +1 -1
- data/lib/puppet/provider/exec.rb +6 -2
- data/lib/puppet/provider/nameservice/directoryservice.rb +1 -1
- data/lib/puppet/provider/nameservice/pw.rb +2 -2
- data/lib/puppet/provider/package/apt.rb +5 -1
- data/lib/puppet/provider/package/dnfmodule.rb +87 -0
- data/lib/puppet/provider/package/dpkg.rb +31 -17
- data/lib/puppet/provider/package/openbsd.rb +1 -1
- data/lib/puppet/provider/package/pip.rb +34 -9
- data/lib/puppet/provider/package/portage.rb +1 -1
- data/lib/puppet/provider/package/rpm.rb +5 -5
- data/lib/puppet/provider/package/windows/package.rb +1 -1
- data/lib/puppet/provider/package/yum.rb +1 -1
- data/lib/puppet/provider/parsedfile.rb +1 -1
- data/lib/puppet/provider/service/daemontools.rb +9 -9
- data/lib/puppet/provider/service/openbsd.rb +1 -1
- data/lib/puppet/provider/service/rcng.rb +2 -2
- data/lib/puppet/provider/service/runit.rb +2 -8
- data/lib/puppet/provider/service/systemd.rb +10 -10
- data/lib/puppet/provider/user/directoryservice.rb +1 -1
- data/lib/puppet/provider/user/user_role_add.rb +1 -1
- data/lib/puppet/provider/user/useradd.rb +22 -13
- data/lib/puppet/provider/user/windows_adsi.rb +4 -5
- data/lib/puppet/reference/indirection.rb +2 -2
- data/lib/puppet/reference/metaparameter.rb +1 -3
- data/lib/puppet/reference/providers.rb +1 -1
- data/lib/puppet/reference/type.rb +3 -9
- data/lib/puppet/reports.rb +1 -1
- data/lib/puppet/resource.rb +1 -1
- data/lib/puppet/resource/catalog.rb +1 -1
- data/lib/puppet/rest/errors.rb +1 -0
- data/lib/puppet/rest/response.rb +1 -0
- data/lib/puppet/rest/route.rb +1 -0
- data/lib/puppet/rest/routes.rb +3 -0
- data/lib/puppet/runtime.rb +25 -0
- data/lib/puppet/settings.rb +3 -3
- data/lib/puppet/settings/environment_conf.rb +1 -0
- data/lib/puppet/ssl/host.rb +1 -1
- data/lib/puppet/ssl/oids.rb +1 -1
- data/lib/puppet/ssl/state_machine.rb +23 -15
- data/lib/puppet/test/test_helper.rb +1 -1
- data/lib/puppet/transaction/report.rb +1 -1
- data/lib/puppet/trusted_external.rb +13 -0
- data/lib/puppet/type.rb +1 -3
- data/lib/puppet/type/exec.rb +7 -3
- data/lib/puppet/type/file.rb +1 -2
- data/lib/puppet/type/file/source.rb +2 -2
- data/lib/puppet/type/package.rb +10 -3
- data/lib/puppet/type/schedule.rb +1 -1
- data/lib/puppet/type/service.rb +1 -1
- data/lib/puppet/util.rb +2 -2
- data/lib/puppet/util/command_line/trollop.rb +1 -1
- data/lib/puppet/util/http_proxy.rb +2 -10
- data/lib/puppet/util/log.rb +2 -2
- data/lib/puppet/util/log/destinations.rb +2 -2
- data/lib/puppet/util/logging.rb +2 -2
- data/lib/puppet/util/metric.rb +2 -2
- data/lib/puppet/util/platform.rb +15 -4
- data/lib/puppet/util/provider_features.rb +2 -4
- data/lib/puppet/util/rdoc.rb +1 -1
- data/lib/puppet/util/reference.rb +1 -1
- data/lib/puppet/util/resource_template.rb +1 -1
- data/lib/puppet/util/selinux.rb +3 -1
- data/lib/puppet/util/windows/registry.rb +7 -5
- data/lib/puppet/vendor.rb +1 -1
- data/lib/puppet/vendor/require_vendored.rb +0 -1
- data/lib/puppet/version.rb +1 -1
- data/lib/puppet/x509/cert_provider.rb +4 -1
- data/locales/puppet.pot +279 -203
- data/man/man5/puppet.conf.5 +30 -8
- data/man/man8/puppet-agent.8 +4 -1
- data/man/man8/puppet-apply.8 +1 -1
- data/man/man8/puppet-catalog.8 +1 -1
- data/man/man8/puppet-config.8 +1 -1
- data/man/man8/puppet-describe.8 +1 -1
- data/man/man8/puppet-device.8 +1 -1
- data/man/man8/puppet-doc.8 +1 -1
- data/man/man8/puppet-epp.8 +1 -1
- data/man/man8/puppet-facts.8 +1 -1
- data/man/man8/puppet-filebucket.8 +1 -1
- data/man/man8/puppet-generate.8 +1 -1
- data/man/man8/puppet-help.8 +1 -1
- data/man/man8/puppet-key.8 +1 -1
- data/man/man8/puppet-lookup.8 +1 -1
- data/man/man8/puppet-man.8 +1 -1
- data/man/man8/puppet-module.8 +1 -1
- data/man/man8/puppet-node.8 +1 -1
- data/man/man8/puppet-parser.8 +1 -1
- data/man/man8/puppet-plugin.8 +1 -1
- data/man/man8/puppet-report.8 +1 -1
- data/man/man8/puppet-resource.8 +1 -1
- data/man/man8/puppet-script.8 +1 -1
- data/man/man8/puppet-ssl.8 +1 -1
- data/man/man8/puppet-status.8 +1 -1
- data/man/man8/puppet.8 +2 -2
- data/spec/fixtures/unit/provider/package/dnfmodule/dnf-module-list-installed.txt +11 -0
- data/spec/integration/configurer_spec.rb +52 -0
- data/spec/lib/puppet/certificate_factory.rb +2 -2
- data/spec/spec_helper.rb +24 -0
- data/spec/unit/application/device_spec.rb +6 -0
- data/spec/unit/application/ssl_spec.rb +4 -7
- data/spec/unit/configurer_spec.rb +1 -0
- data/spec/unit/context/trusted_information_spec.rb +41 -2
- data/spec/unit/http/client_spec.rb +440 -0
- data/spec/unit/http/resolver_spec.rb +45 -0
- data/spec/unit/http/service/ca_spec.rb +106 -0
- data/spec/unit/http/service_spec.rb +32 -0
- data/spec/unit/http/session_spec.rb +102 -0
- data/spec/unit/indirector/resource/ral_spec.rb +4 -4
- data/spec/unit/network/http/connection_spec.rb +119 -145
- data/spec/unit/network/http/site_spec.rb +7 -0
- data/spec/unit/parser/scope_spec.rb +10 -0
- data/spec/unit/pops/loaders/loaders_spec.rb +13 -2
- data/spec/unit/pops/loaders/module_loaders_spec.rb +37 -0
- data/spec/unit/provider/exec_spec.rb +209 -0
- data/spec/unit/provider/package/dnfmodule_spec.rb +186 -0
- data/spec/unit/provider/package/dpkg_spec.rb +238 -78
- data/spec/unit/provider/package/pip_spec.rb +51 -6
- data/spec/unit/provider/service/daemontools_spec.rb +24 -0
- data/spec/unit/provider/service/runit_spec.rb +24 -0
- data/spec/unit/provider/service/systemd_spec.rb +25 -25
- data/spec/unit/provider/user/useradd_spec.rb +46 -0
- data/spec/unit/ssl/host_spec.rb +0 -5
- data/spec/unit/ssl/state_machine_spec.rb +16 -10
- data/spec/unit/type/exec_spec.rb +6 -12
- data/spec/unit/type/file_spec.rb +9 -4
- data/spec/unit/type/package_spec.rb +5 -0
- data/spec/unit/util/execution_spec.rb +16 -0
- data/spec/unit/util/http_proxy_spec.rb +79 -27
- data/spec/unit/util/log/destinations_spec.rb +7 -3
- metadata +45 -22
- data/lib/puppet/pops/loader/null_loader.rb +0 -60
- data/lib/puppet/vendor/deep_merge/CHANGELOG +0 -45
- data/lib/puppet/vendor/deep_merge/Gemfile +0 -3
- data/lib/puppet/vendor/deep_merge/LICENSE +0 -21
- data/lib/puppet/vendor/deep_merge/PUPPET_README.md +0 -6
- data/lib/puppet/vendor/deep_merge/README.md +0 -113
- data/lib/puppet/vendor/deep_merge/Rakefile +0 -19
- data/lib/puppet/vendor/deep_merge/deep_merge.gemspec +0 -35
- data/lib/puppet/vendor/deep_merge/lib/deep_merge.rb +0 -2
- data/lib/puppet/vendor/deep_merge/lib/deep_merge/core.rb +0 -210
- data/lib/puppet/vendor/deep_merge/lib/deep_merge/deep_merge_hash.rb +0 -28
- data/lib/puppet/vendor/deep_merge/lib/deep_merge/rails_compat.rb +0 -27
- data/lib/puppet/vendor/deep_merge/test/test_deep_merge.rb +0 -608
- data/lib/puppet/vendor/load_deep_merge.rb +0 -1
- data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_get/should_yield_to_the_block.yml +0 -24
- data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_head/should_yield_to_the_block.yml +0 -24
- data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_post/should_yield_to_the_block.yml +0 -24
@@ -86,4 +86,11 @@ describe Puppet::Network::HTTP::Site do
|
|
86
86
|
expect(new_site.host).to eq('host2')
|
87
87
|
expect(new_site.port).to eq(443)
|
88
88
|
end
|
89
|
+
|
90
|
+
it 'creates a site from a URI' do
|
91
|
+
site = create_site('https', 'rubygems.org', 443)
|
92
|
+
uri = URI.parse('https://rubygems.org/gems/puppet/')
|
93
|
+
|
94
|
+
expect(described_class.from_uri(uri)).to eq(site)
|
95
|
+
end
|
89
96
|
end
|
@@ -680,5 +680,15 @@ describe Puppet::Parser::Scope do
|
|
680
680
|
@scope.setvar("orange", :undef)
|
681
681
|
expect(@scope.to_hash).to eq({'pear' => :green, 'apple' => :red })
|
682
682
|
end
|
683
|
+
|
684
|
+
it "should not delete values that are :undef in inner scope when include_undef is true" do
|
685
|
+
@scope.new_ephemeral true
|
686
|
+
@scope.setvar("orange", :tangerine)
|
687
|
+
@scope.setvar("pear", :green)
|
688
|
+
@scope.new_ephemeral true
|
689
|
+
@scope.setvar("apple", :red)
|
690
|
+
@scope.setvar("orange", :undef)
|
691
|
+
expect(@scope.to_hash(true, true)).to eq({'pear' => :green, 'apple' => :red, 'orange' => :undef })
|
692
|
+
end
|
683
693
|
end
|
684
694
|
end
|
@@ -52,6 +52,10 @@ describe 'loaders' do
|
|
52
52
|
|
53
53
|
# Loaders caches the puppet_system_loader, must reset between tests
|
54
54
|
|
55
|
+
before :each do
|
56
|
+
allow(File).to receive(:read).and_call_original
|
57
|
+
end
|
58
|
+
|
55
59
|
context 'when loading pp resource types using auto loading' do
|
56
60
|
let(:pp_resources) { config_dir('pp_resources') }
|
57
61
|
let(:environments) { Puppet::Environments::Directories.new(my_fixture_dir, []) }
|
@@ -100,6 +104,11 @@ describe 'loaders' do
|
|
100
104
|
expect(loaders.puppet_cache_loader()).to be_a(Puppet::Pops::Loader::ModuleLoaders::LibRootedFileBased)
|
101
105
|
end
|
102
106
|
|
107
|
+
it 'creates a cached_puppet loader that can load version 4 functions, version 3 functions, and data types, in that order' do
|
108
|
+
loaders = Puppet::Pops::Loaders.new(empty_test_env, true)
|
109
|
+
expect(loaders.puppet_cache_loader.loadables).to eq([:func_4x, :func_3x, :datatype])
|
110
|
+
end
|
111
|
+
|
103
112
|
it 'does not create a cached_puppet loader when for_agent is the default false value' do
|
104
113
|
loaders = Puppet::Pops::Loaders.new(empty_test_env)
|
105
114
|
expect(loaders.puppet_cache_loader()).to be(nil)
|
@@ -450,7 +459,9 @@ describe 'loaders' do
|
|
450
459
|
end
|
451
460
|
|
452
461
|
it "a function with syntax error has helpful error message" do
|
453
|
-
expect {
|
462
|
+
expect {
|
463
|
+
loader.load_typed(typed_name(:function, 'func_with_syntax_error'))
|
464
|
+
}.to raise_error(/syntax error, unexpected (keyword_)?end/)
|
454
465
|
end
|
455
466
|
end
|
456
467
|
|
@@ -487,7 +498,7 @@ describe 'loaders' do
|
|
487
498
|
end
|
488
499
|
|
489
500
|
it "to self inside function body is reported as an error" do
|
490
|
-
expect {
|
501
|
+
expect {
|
491
502
|
f = loader.load_typed(typed_name(:function, 'bad_func_load4')).value
|
492
503
|
f.call(scope)
|
493
504
|
}.to raise_error(/Illegal method definition.*'bad_func_load4_illegal_method'/)
|
@@ -163,6 +163,43 @@ describe 'FileBased module loader' do
|
|
163
163
|
expect(module_loader.load_typed(typed_name(:task, 'testmodule::baz'))).not_to be_nil
|
164
164
|
expect { module_loader.load_typed(typed_name(:task, 'testmodule::qux')) }.to raise_error(/No source besides task metadata was found/)
|
165
165
|
end
|
166
|
+
|
167
|
+
it 'raises and error when `parameters` is not a hash' do
|
168
|
+
metadata = { 'parameters' => 'foo' }
|
169
|
+
module_dir = dir_containing('testmodule', 'tasks' => {'foo.py' => '', 'foo.json' => metadata.to_json})
|
170
|
+
|
171
|
+
module_loader = Puppet::Pops::Loader::ModuleLoaders.module_loader_from(static_loader, loaders, 'testmodule', module_dir)
|
172
|
+
expect{module_loader.load_typed(typed_name(:task, 'testmodule::foo'))}
|
173
|
+
.to raise_error(Puppet::ParseError, /Failed to load metadata for task testmodule::foo: 'parameters' must be a hash/)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'raises and error when `implementations` `requirements` key is not an array' do
|
177
|
+
metadata = { 'implementations' => { 'name' => 'foo.py', 'requirements' => 'foo'} }
|
178
|
+
module_dir = dir_containing('testmodule', 'tasks' => {'foo.py' => '', 'foo.json' => metadata.to_json})
|
179
|
+
|
180
|
+
module_loader = Puppet::Pops::Loader::ModuleLoaders.module_loader_from(static_loader, loaders, 'testmodule', module_dir)
|
181
|
+
expect{module_loader.load_typed(typed_name(:task, 'testmodule::foo'))}
|
182
|
+
.to raise_error(Puppet::Module::Task::InvalidMetadata,
|
183
|
+
/Task metadata for task testmodule::foo does not specify implementations as an array/)
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'raises and error when top-level `files` is not an array' do
|
187
|
+
metadata = { 'files' => 'foo' }
|
188
|
+
module_dir = dir_containing('testmodule', 'tasks' => {'foo.py' => '', 'foo.json' => metadata.to_json})
|
189
|
+
|
190
|
+
module_loader = Puppet::Pops::Loader::ModuleLoaders.module_loader_from(static_loader, loaders, 'testmodule', module_dir)
|
191
|
+
expect{module_loader.load_typed(typed_name(:task, 'testmodule::foo'))}
|
192
|
+
.to raise_error(Puppet::Module::Task::InvalidMetadata, /The 'files' task metadata expects an array, got foo/)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'raises and error when `files` nested in `interpreters` is not an array' do
|
196
|
+
metadata = { 'implementations' => [{'name' => 'foo.py', 'files' => 'foo'}] }
|
197
|
+
module_dir = dir_containing('testmodule', 'tasks' => {'foo.py' => '', 'foo.json' => metadata.to_json})
|
198
|
+
|
199
|
+
module_loader = Puppet::Pops::Loader::ModuleLoaders.module_loader_from(static_loader, loaders, 'testmodule', module_dir)
|
200
|
+
expect{module_loader.load_typed(typed_name(:task, 'testmodule::foo'))}
|
201
|
+
.to raise_error(Puppet::Module::Task::InvalidMetadata, /The 'files' task metadata expects an array, got foo/)
|
202
|
+
end
|
166
203
|
end
|
167
204
|
|
168
205
|
def typed_name(type, name)
|
@@ -1,7 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'puppet/provider/exec'
|
3
|
+
require 'puppet_spec/compiler'
|
4
|
+
require 'puppet_spec/files'
|
3
5
|
|
4
6
|
describe Puppet::Provider::Exec do
|
7
|
+
include PuppetSpec::Compiler
|
8
|
+
include PuppetSpec::Files
|
9
|
+
|
5
10
|
describe "#extractexe" do
|
6
11
|
it "should return the first element of an array" do
|
7
12
|
expect(subject.extractexe(['one', 'two'])).to eq('one')
|
@@ -31,4 +36,208 @@ describe Puppet::Provider::Exec do
|
|
31
36
|
end
|
32
37
|
end
|
33
38
|
end
|
39
|
+
|
40
|
+
context "when handling sensitive data" do
|
41
|
+
before :each do
|
42
|
+
Puppet[:log_level] = 'debug'
|
43
|
+
end
|
44
|
+
|
45
|
+
let(:supersecret) { 'supersecret' }
|
46
|
+
let(:path) do
|
47
|
+
if Puppet::Util::Platform.windows?
|
48
|
+
# The `apply_compiled_manifest` helper doesn't add the `path` fact, so
|
49
|
+
# we can't reference that in our manifest. Windows PATHs can contain
|
50
|
+
# double quotes and trailing backslashes, which confuse HEREDOC
|
51
|
+
# interpolation below. So sanitize it:
|
52
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).map do |dir|
|
53
|
+
dir.gsub(/"/, '\"').gsub(/\\$/, '')
|
54
|
+
end.join(File::PATH_SEPARATOR)
|
55
|
+
else
|
56
|
+
ENV['PATH']
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def ruby_exit_0
|
61
|
+
"ruby -e 'exit 0'"
|
62
|
+
end
|
63
|
+
|
64
|
+
def echo_from_ruby_exit_0(message)
|
65
|
+
# Escape double quotes due to HEREDOC interpolation below
|
66
|
+
"ruby -e 'puts \"#{message}\"; exit 0'".gsub(/"/, '\"')
|
67
|
+
end
|
68
|
+
|
69
|
+
def echo_from_ruby_exit_1(message)
|
70
|
+
# Escape double quotes due to HEREDOC interpolation below
|
71
|
+
"ruby -e 'puts \"#{message}\"; exit 1'".gsub(/"/, '\"')
|
72
|
+
end
|
73
|
+
|
74
|
+
context "when validating the command" do
|
75
|
+
it "redacts the arguments if the command is relative" do
|
76
|
+
expect {
|
77
|
+
apply_compiled_manifest(<<-MANIFEST)
|
78
|
+
exec { 'echo':
|
79
|
+
command => Sensitive.new('echo #{supersecret}')
|
80
|
+
}
|
81
|
+
MANIFEST
|
82
|
+
}.to raise_error do |err|
|
83
|
+
expect(err).to be_a(Puppet::Error)
|
84
|
+
expect(err.message).to match(/'echo' is not qualified and no path was specified. Please qualify the command or specify a path./)
|
85
|
+
expect(err.message).to_not match(/#{supersecret}/)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it "redacts the arguments if the command is a directory" do
|
90
|
+
dir = tmpdir('exec')
|
91
|
+
apply_compiled_manifest(<<-MANIFEST)
|
92
|
+
exec { 'echo':
|
93
|
+
command => Sensitive.new('#{dir} #{supersecret}'),
|
94
|
+
}
|
95
|
+
MANIFEST
|
96
|
+
expect(@logs).to include(an_object_having_attributes(level: :err, message: /'#{dir}' is a directory, not a file/))
|
97
|
+
expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
|
98
|
+
end
|
99
|
+
|
100
|
+
it "redacts the arguments if the command isn't executable" do
|
101
|
+
file = tmpfile('exec')
|
102
|
+
Puppet::FileSystem.touch(file)
|
103
|
+
Puppet::FileSystem.chmod(0644, file)
|
104
|
+
|
105
|
+
apply_compiled_manifest(<<-MANIFEST)
|
106
|
+
exec { 'echo':
|
107
|
+
command => Sensitive.new('#{file} #{supersecret}'),
|
108
|
+
}
|
109
|
+
MANIFEST
|
110
|
+
# Execute permission works differently on Windows, but execute will fail since the
|
111
|
+
# file doesn't have a valid extension and isn't a valid executable. The raised error
|
112
|
+
# will be Errno::EIO, which is not useful. The Windows execute code needs to raise
|
113
|
+
# Puppet::Util::Windows::Error so the Win32 error message is preserved.
|
114
|
+
pending("PUP-3561 Needs to raise a meaningful Puppet::Error") if Puppet::Util::Platform.windows?
|
115
|
+
expect(@logs).to include(an_object_having_attributes(level: :err, message: /'#{file}' is not executable/))
|
116
|
+
expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
|
117
|
+
end
|
118
|
+
|
119
|
+
it "redacts the arguments if the relative command cannot be resolved using the path parameter" do
|
120
|
+
file = File.basename(tmpfile('exec'))
|
121
|
+
dir = tmpdir('exec')
|
122
|
+
|
123
|
+
apply_compiled_manifest(<<-MANIFEST)
|
124
|
+
exec { 'echo':
|
125
|
+
command => Sensitive.new('#{file} #{supersecret}'),
|
126
|
+
path => "#{dir}",
|
127
|
+
}
|
128
|
+
MANIFEST
|
129
|
+
expect(@logs).to include(an_object_having_attributes(level: :err, message: /Could not find command '#{file}'/))
|
130
|
+
expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it "redacts the command on success", unless: Puppet::Util::Platform.jruby? do
|
135
|
+
command = echo_from_ruby_exit_0(supersecret)
|
136
|
+
|
137
|
+
apply_compiled_manifest(<<-MANIFEST)
|
138
|
+
exec { 'true':
|
139
|
+
command => Sensitive.new("#{command}"),
|
140
|
+
path => "#{path}",
|
141
|
+
}
|
142
|
+
MANIFEST
|
143
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing '[redacted]'", source: /Exec\[true\]/))
|
144
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing: '[redacted]'", source: "Puppet"))
|
145
|
+
expect(@logs).to include(an_object_having_attributes(level: :notice, message: "executed successfully"))
|
146
|
+
expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
|
147
|
+
end
|
148
|
+
|
149
|
+
it "redacts the command on failure", unless: Puppet::Util::Platform.jruby? do
|
150
|
+
command = echo_from_ruby_exit_1(supersecret)
|
151
|
+
|
152
|
+
apply_compiled_manifest(<<-MANIFEST)
|
153
|
+
exec { 'false':
|
154
|
+
command => Sensitive.new("#{command}"),
|
155
|
+
path => "#{path}",
|
156
|
+
}
|
157
|
+
MANIFEST
|
158
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing '[redacted]'", source: /Exec\[false\]/))
|
159
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing: '[redacted]'", source: "Puppet"))
|
160
|
+
expect(@logs).to include(an_object_having_attributes(level: :err, message: "[command redacted] returned 1 instead of one of [0]"))
|
161
|
+
expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
|
162
|
+
end
|
163
|
+
|
164
|
+
context "when handling checks", unless: Puppet::Util::Platform.jruby? do
|
165
|
+
let(:onlyifsecret) { "onlyifsecret" }
|
166
|
+
let(:unlesssecret) { "unlesssecret" }
|
167
|
+
|
168
|
+
it "redacts command and onlyif outputs" do
|
169
|
+
onlyif = echo_from_ruby_exit_0(onlyifsecret)
|
170
|
+
|
171
|
+
apply_compiled_manifest(<<-MANIFEST)
|
172
|
+
exec { 'true':
|
173
|
+
command => Sensitive.new("#{ruby_exit_0}"),
|
174
|
+
onlyif => Sensitive.new("#{onlyif}"),
|
175
|
+
path => "#{path}",
|
176
|
+
}
|
177
|
+
MANIFEST
|
178
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing check '[redacted]'"))
|
179
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing '[redacted]'", source: /Exec\[true\]/))
|
180
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing: '[redacted]'", source: "Puppet"))
|
181
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "[output redacted]"))
|
182
|
+
expect(@logs).to include(an_object_having_attributes(level: :notice, message: "executed successfully"))
|
183
|
+
expect(@logs).to_not include(an_object_having_attributes(message: /#{onlyifsecret}/))
|
184
|
+
end
|
185
|
+
|
186
|
+
it "redacts the command that would have been executed but didn't due to onlyif" do
|
187
|
+
command = echo_from_ruby_exit_0(supersecret)
|
188
|
+
onlyif = echo_from_ruby_exit_1(onlyifsecret)
|
189
|
+
|
190
|
+
apply_compiled_manifest(<<-MANIFEST)
|
191
|
+
exec { 'true':
|
192
|
+
command => Sensitive.new("#{command}"),
|
193
|
+
onlyif => Sensitive.new("#{onlyif}"),
|
194
|
+
path => "#{path}",
|
195
|
+
}
|
196
|
+
MANIFEST
|
197
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing check '[redacted]'"))
|
198
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing: '[redacted]'", source: "Puppet"))
|
199
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "[output redacted]"))
|
200
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "'[command redacted]' won't be executed because of failed check 'onlyif'"))
|
201
|
+
expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
|
202
|
+
expect(@logs).to_not include(an_object_having_attributes(message: /#{onlyifsecret}/))
|
203
|
+
end
|
204
|
+
|
205
|
+
it "redacts command and unless outputs" do
|
206
|
+
unlesscmd = echo_from_ruby_exit_1(unlesssecret)
|
207
|
+
|
208
|
+
apply_compiled_manifest(<<-MANIFEST)
|
209
|
+
exec { 'true':
|
210
|
+
command => Sensitive.new("#{ruby_exit_0}"),
|
211
|
+
unless => Sensitive.new("#{unlesscmd}"),
|
212
|
+
path => "#{path}",
|
213
|
+
}
|
214
|
+
MANIFEST
|
215
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing check '[redacted]'"))
|
216
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing '[redacted]'", source: /Exec\[true\]/))
|
217
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing: '[redacted]'", source: "Puppet"))
|
218
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "[output redacted]"))
|
219
|
+
expect(@logs).to include(an_object_having_attributes(level: :notice, message: "executed successfully"))
|
220
|
+
expect(@logs).to_not include(an_object_having_attributes(message: /#{unlesssecret}/))
|
221
|
+
end
|
222
|
+
|
223
|
+
it "redacts the command that would have been executed but didn't due to unless" do
|
224
|
+
command = echo_from_ruby_exit_0(supersecret)
|
225
|
+
unlesscmd = echo_from_ruby_exit_0(unlesssecret)
|
226
|
+
|
227
|
+
apply_compiled_manifest(<<-MANIFEST)
|
228
|
+
exec { 'true':
|
229
|
+
command => Sensitive.new("#{command}"),
|
230
|
+
unless => Sensitive.new("#{unlesscmd}"),
|
231
|
+
path => "#{path}",
|
232
|
+
}
|
233
|
+
MANIFEST
|
234
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing check '[redacted]'"))
|
235
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Executing: '[redacted]'", source: "Puppet"))
|
236
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "[output redacted]"))
|
237
|
+
expect(@logs).to include(an_object_having_attributes(level: :debug, message: "'[command redacted]' won't be executed because of failed check 'unless'"))
|
238
|
+
expect(@logs).to_not include(an_object_having_attributes(message: /#{supersecret}/))
|
239
|
+
expect(@logs).to_not include(an_object_having_attributes(message: /#{unlesssecret}/))
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
34
243
|
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Puppet::Type.type(:package).provider(:dnfmodule) do
|
4
|
+
include PuppetSpec::Fixtures
|
5
|
+
|
6
|
+
let(:dnf_version) do
|
7
|
+
<<-DNF_OUTPUT
|
8
|
+
4.0.9
|
9
|
+
Installed: dnf-0:4.0.9.2-5.el8.noarch at Wed 29 May 2019 07:05:05 AM GMT
|
10
|
+
Built : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla> at Thu 14 Feb 2019 12:04:07 PM GMT
|
11
|
+
|
12
|
+
Installed: rpm-0:4.14.2-9.el8.x86_64 at Wed 29 May 2019 07:04:33 AM GMT
|
13
|
+
Built : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla> at Thu 20 Dec 2018 01:30:03 PM GMT
|
14
|
+
DNF_OUTPUT
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:execute_options) do
|
18
|
+
{:failonfail => true, :combine => true, :custom_environment => {}}
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:packages) { File.read(my_fixture("dnf-module-list-installed.txt")) }
|
22
|
+
let(:dnf_path) { '/usr/bin/dnf' }
|
23
|
+
|
24
|
+
before(:each) { allow(Puppet::Util).to receive(:which).with('/usr/bin/dnf').and_return(dnf_path) }
|
25
|
+
|
26
|
+
it "should have lower specificity" do
|
27
|
+
allow(Facter).to receive(:value).with(:osfamily).and_return(:redhat)
|
28
|
+
allow(Facter).to receive(:value).with(:operatingsystem).and_return(:redhat)
|
29
|
+
allow(Facter).to receive(:value).with(:operatingsystemmajrelease).and_return('8')
|
30
|
+
expect(described_class.specificity).to be < 200
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "should be an opt-in provider" do
|
34
|
+
Array(4..8).each do |ver|
|
35
|
+
it "should not be default for redhat #{ver}" do
|
36
|
+
allow(Facter).to receive(:value).with(:operatingsystem).and_return('redhat')
|
37
|
+
allow(Facter).to receive(:value).with(:osfamily).and_return('redhat')
|
38
|
+
allow(Facter).to receive(:value).with(:operatingsystemmajrelease).and_return(ver.to_s)
|
39
|
+
expect(described_class).not_to be_default
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "handling dnf versions" do
|
45
|
+
before(:each) do
|
46
|
+
expect(Puppet::Type::Package::ProviderDnfmodule).to receive(:execute)
|
47
|
+
.with(["/usr/bin/dnf", "--version"])
|
48
|
+
.and_return(dnf_version).at_most(:once)
|
49
|
+
expect(Puppet::Util::Execution).to receive(:execute)
|
50
|
+
.with(["/usr/bin/dnf", "--version"], execute_options)
|
51
|
+
.and_return(Puppet::Util::Execution::ProcessOutput.new(dnf_version, 0))
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "with a supported dnf version" do
|
55
|
+
it "correctly parses the version" do
|
56
|
+
expect(described_class.current_version).to eq('4.0.9')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "with an unsupported dnf version" do
|
61
|
+
let(:dnf_version) do
|
62
|
+
<<-DNF_OUTPUT
|
63
|
+
2.7.5
|
64
|
+
Installed: dnf-0:2.7.5-12.fc28.noarch at Mon 13 Aug 2018 11:05:27 PM GMT
|
65
|
+
Built : Fedora Project at Wed 18 Apr 2018 02:29:51 PM GMT
|
66
|
+
|
67
|
+
Installed: rpm-0:4.14.1-7.fc28.x86_64 at Mon 13 Aug 2018 11:05:25 PM GMT
|
68
|
+
Built : Fedora Project at Mon 19 Feb 2018 09:29:01 AM GMT
|
69
|
+
DNF_OUTPUT
|
70
|
+
end
|
71
|
+
|
72
|
+
before(:each) { described_class.instance_variable_set("@current_version", nil) }
|
73
|
+
|
74
|
+
it "correctly parses the version" do
|
75
|
+
expect(described_class.current_version).to eq('2.7.5')
|
76
|
+
end
|
77
|
+
|
78
|
+
it "raises an error when attempting prefetch" do
|
79
|
+
expect { described_class.prefetch('anything') }.to raise_error(Puppet::Error, "Modules are not supported on DNF versions lower than 3.0.1")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "when installing a module" do
|
85
|
+
let(:name) { 'baz' }
|
86
|
+
|
87
|
+
let(:resource) do
|
88
|
+
Puppet::Type.type(:package).new(
|
89
|
+
:name => name,
|
90
|
+
:provider => 'dnfmodule',
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
let(:provider) do
|
95
|
+
provider = described_class.new
|
96
|
+
provider.resource = resource
|
97
|
+
provider
|
98
|
+
end
|
99
|
+
|
100
|
+
describe 'provider features' do
|
101
|
+
it { is_expected.to be_versionable }
|
102
|
+
it { is_expected.to be_installable }
|
103
|
+
it { is_expected.to be_uninstallable }
|
104
|
+
end
|
105
|
+
|
106
|
+
context "when installing a new module" do
|
107
|
+
before do
|
108
|
+
provider.instance_variable_get('@property_hash')[:ensure] = :absent
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should not reset the module stream when package is absent" do
|
112
|
+
resource[:ensure] = :present
|
113
|
+
expect(provider).not_to receive(:uninstall)
|
114
|
+
expect(provider).to receive(:execute)
|
115
|
+
provider.install
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should not reset the module stream when package is purged" do
|
119
|
+
provider.instance_variable_get('@property_hash')[:ensure] = :purged
|
120
|
+
resource[:ensure] = :present
|
121
|
+
expect(provider).not_to receive(:uninstall)
|
122
|
+
expect(provider).to receive(:execute)
|
123
|
+
provider.install
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should install the default stream and flavor" do
|
127
|
+
resource[:ensure] = :present
|
128
|
+
expect(provider).to receive(:execute).with(array_including('baz'))
|
129
|
+
provider.install
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should install a specific stream" do
|
133
|
+
resource[:ensure] = '9.6'
|
134
|
+
expect(provider).to receive(:execute).with(array_including('baz:9.6'))
|
135
|
+
provider.install
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should install a specific flavor" do
|
139
|
+
resource[:ensure] = :present
|
140
|
+
resource[:flavor] = 'minimal'
|
141
|
+
expect(provider).to receive(:execute).with(array_including('baz/minimal'))
|
142
|
+
provider.install
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should install a specific flavor and stream" do
|
146
|
+
resource[:ensure] = '9.6'
|
147
|
+
resource[:flavor] = 'minimal'
|
148
|
+
expect(provider).to receive(:execute).with(array_including('baz:9.6/minimal'))
|
149
|
+
provider.install
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context "when ensuring a specific version on top of another stream" do
|
154
|
+
before do
|
155
|
+
provider.instance_variable_get('@property_hash')[:ensure] = '9.6'
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should remove existing packages and reset the module stream before installing" do
|
159
|
+
resource[:ensure] = '10'
|
160
|
+
expect(provider).to receive(:execute).thrice.with(array_including(/remove|reset|install/))
|
161
|
+
provider.install
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "parsing the output of module list --installed" do
|
167
|
+
before { allow(described_class).to receive(:command).with(:dnf).and_return(dnf_path) }
|
168
|
+
|
169
|
+
it "returns an array of installed modules" do
|
170
|
+
allow(Puppet::Util::Execution).to receive(:execute)
|
171
|
+
.with("/usr/bin/dnf module list --installed -d 0 -e 1")
|
172
|
+
.and_return(packages)
|
173
|
+
|
174
|
+
installed_packages = described_class.instances.map { |package| package.properties }
|
175
|
+
expected_packages = [{name: "gimp", ensure: "2.8", flavor: "devel", :provider => :dnfmodule},
|
176
|
+
{name: "mariadb", ensure: "10.3", flavor: "client", :provider => :dnfmodule},
|
177
|
+
{name: "nodejs", ensure: "10", flavor: "minimal", :provider => :dnfmodule},
|
178
|
+
{name: "perl", ensure: "5.26", flavor: "minimal", :provider => :dnfmodule},
|
179
|
+
{name: "postgresql", ensure: "10", flavor: "server", :provider => :dnfmodule},
|
180
|
+
{name: "rust-toolset", ensure: "rhel8", flavor: "common", :provider => :dnfmodule},
|
181
|
+
{name: "subversion", ensure: "1.10", flavor: "server", :provider => :dnfmodule}]
|
182
|
+
|
183
|
+
expect(installed_packages).to eql(expected_packages)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|