puppet 6.15.0 → 6.16.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.

Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +2 -7
  3. data/Gemfile.lock +17 -14
  4. data/lib/puppet.rb +32 -8
  5. data/lib/puppet/agent.rb +18 -4
  6. data/lib/puppet/application/agent.rb +1 -2
  7. data/lib/puppet/application/device.rb +1 -1
  8. data/lib/puppet/application/plugin.rb +1 -0
  9. data/lib/puppet/application/ssl.rb +1 -1
  10. data/lib/puppet/configurer.rb +2 -2
  11. data/lib/puppet/context/trusted_information.rb +14 -8
  12. data/lib/puppet/daemon.rb +13 -27
  13. data/lib/puppet/defaults.rb +19 -0
  14. data/lib/puppet/face/facts.rb +1 -1
  15. data/lib/puppet/face/help.rb +29 -3
  16. data/lib/puppet/face/module/search.rb +5 -0
  17. data/lib/puppet/face/plugin.rb +1 -1
  18. data/lib/puppet/file_serving/http_metadata.rb +1 -1
  19. data/lib/puppet/file_system/uniquefile.rb +4 -0
  20. data/lib/puppet/forge/repository.rb +7 -6
  21. data/lib/puppet/functions/filter.rb +1 -0
  22. data/lib/puppet/http/client.rb +22 -11
  23. data/lib/puppet/http/external_client.rb +0 -6
  24. data/lib/puppet/indirector/file_content/http.rb +5 -0
  25. data/lib/puppet/indirector/file_metadata/http.rb +4 -4
  26. data/lib/puppet/indirector/rest.rb +7 -1
  27. data/lib/puppet/network/http/compression.rb +7 -0
  28. data/lib/puppet/network/http/connection.rb +2 -0
  29. data/lib/puppet/network/http/connection_adapter.rb +182 -0
  30. data/lib/puppet/network/http/nocache_pool.rb +1 -0
  31. data/lib/puppet/network/http_pool.rb +2 -2
  32. data/lib/puppet/pal/catalog_compiler.rb +5 -0
  33. data/lib/puppet/pal/pal_impl.rb +4 -1
  34. data/lib/puppet/parser/compiler.rb +28 -25
  35. data/lib/puppet/parser/functions/filter.rb +1 -0
  36. data/lib/puppet/provider/package/aix.rb +17 -2
  37. data/lib/puppet/provider/package/apt.rb +4 -1
  38. data/lib/puppet/provider/package/dnfmodule.rb +24 -4
  39. data/lib/puppet/provider/package/pip.rb +60 -37
  40. data/lib/puppet/provider/package/portage.rb +2 -2
  41. data/lib/puppet/provider/package/yum.rb +7 -0
  42. data/lib/puppet/provider/package/zypper.rb +59 -1
  43. data/lib/puppet/provider/service/systemd.rb +21 -4
  44. data/lib/puppet/provider/user/useradd.rb +5 -1
  45. data/lib/puppet/reports/http.rb +5 -3
  46. data/lib/puppet/runtime.rb +25 -2
  47. data/lib/puppet/ssl/state_machine.rb +33 -8
  48. data/lib/puppet/ssl/verifier_adapter.rb +9 -1
  49. data/lib/puppet/test/test_helper.rb +1 -1
  50. data/lib/puppet/type/file/source.rb +1 -1
  51. data/lib/puppet/type/package.rb +16 -1
  52. data/lib/puppet/type/service.rb +6 -8
  53. data/lib/puppet/type/user.rb +1 -7
  54. data/lib/puppet/util/autoload.rb +1 -18
  55. data/lib/puppet/util/log/destinations.rb +1 -10
  56. data/lib/puppet/util/package/version/range.rb +4 -1
  57. data/lib/puppet/util/package/version/range/eq.rb +14 -0
  58. data/lib/puppet/version.rb +1 -1
  59. data/locales/puppet.pot +191 -111
  60. data/man/man5/puppet.conf.5 +21 -2
  61. data/man/man8/puppet-agent.8 +1 -1
  62. data/man/man8/puppet-apply.8 +1 -1
  63. data/man/man8/puppet-catalog.8 +1 -1
  64. data/man/man8/puppet-config.8 +1 -1
  65. data/man/man8/puppet-describe.8 +1 -1
  66. data/man/man8/puppet-device.8 +1 -1
  67. data/man/man8/puppet-doc.8 +1 -1
  68. data/man/man8/puppet-epp.8 +1 -1
  69. data/man/man8/puppet-facts.8 +1 -1
  70. data/man/man8/puppet-filebucket.8 +1 -1
  71. data/man/man8/puppet-generate.8 +1 -1
  72. data/man/man8/puppet-help.8 +6 -3
  73. data/man/man8/puppet-key.8 +1 -1
  74. data/man/man8/puppet-lookup.8 +1 -1
  75. data/man/man8/puppet-man.8 +1 -1
  76. data/man/man8/puppet-module.8 +4 -1
  77. data/man/man8/puppet-node.8 +1 -1
  78. data/man/man8/puppet-parser.8 +1 -1
  79. data/man/man8/puppet-plugin.8 +1 -1
  80. data/man/man8/puppet-report.8 +1 -1
  81. data/man/man8/puppet-resource.8 +1 -1
  82. data/man/man8/puppet-script.8 +1 -1
  83. data/man/man8/puppet-ssl.8 +1 -1
  84. data/man/man8/puppet-status.8 +1 -1
  85. data/man/man8/puppet.8 +2 -2
  86. data/spec/fixtures/unit/provider/package/dnfmodule/{dnf-module-list-enabled.txt → dnf-module-list.txt} +6 -0
  87. data/spec/fixtures/unit/provider/package/zypper/zypper-search-uninstalled.out +13 -0
  88. data/spec/integration/application/agent_spec.rb +66 -1
  89. data/spec/integration/application/plugin_spec.rb +23 -0
  90. data/spec/integration/http/client_spec.rb +6 -1
  91. data/spec/integration/network/http_pool_spec.rb +56 -0
  92. data/spec/integration/util/windows/adsi_spec.rb +5 -0
  93. data/spec/lib/puppet_spec/https.rb +6 -0
  94. data/spec/unit/agent_spec.rb +47 -1
  95. data/spec/unit/application/agent_spec.rb +4 -4
  96. data/spec/unit/context/trusted_information_spec.rb +17 -0
  97. data/spec/unit/daemon_spec.rb +5 -64
  98. data/spec/unit/face/module/search_spec.rb +17 -0
  99. data/spec/unit/file_system/uniquefile_spec.rb +11 -0
  100. data/spec/unit/http/client_spec.rb +10 -10
  101. data/spec/unit/http/external_client_spec.rb +9 -9
  102. data/spec/unit/indirector/catalog/compiler_spec.rb +1 -0
  103. data/spec/unit/indirector/file_metadata/http_spec.rb +167 -0
  104. data/spec/unit/indirector/file_metadata/rest_spec.rb +15 -14
  105. data/spec/unit/indirector/rest_spec.rb +13 -0
  106. data/spec/unit/network/http/connection_spec.rb +542 -190
  107. data/spec/unit/network/http/nocache_pool_spec.rb +22 -0
  108. data/spec/unit/network/http_pool_spec.rb +63 -57
  109. data/spec/unit/network/http_spec.rb +1 -1
  110. data/spec/unit/provider/package/aix_spec.rb +29 -0
  111. data/spec/unit/provider/package/dnfmodule_spec.rb +25 -5
  112. data/spec/unit/provider/package/pip_spec.rb +42 -16
  113. data/spec/unit/provider/package/portage_spec.rb +5 -0
  114. data/spec/unit/provider/package/yum_spec.rb +16 -8
  115. data/spec/unit/provider/package/zypper_spec.rb +84 -0
  116. data/spec/unit/provider/service/init_spec.rb +1 -0
  117. data/spec/unit/provider/service/openbsd_spec.rb +9 -0
  118. data/spec/unit/provider/service/openwrt_spec.rb +1 -0
  119. data/spec/unit/provider/service/redhat_spec.rb +9 -0
  120. data/spec/unit/provider/service/systemd_spec.rb +84 -13
  121. data/spec/unit/provider/user/useradd_spec.rb +8 -0
  122. data/spec/unit/puppet_pal_catalog_spec.rb +43 -0
  123. data/spec/unit/puppet_spec.rb +33 -0
  124. data/spec/unit/reports/http_spec.rb +1 -1
  125. data/spec/unit/ssl/state_machine_spec.rb +52 -8
  126. data/spec/unit/type/service_spec.rb +9 -8
  127. data/spec/unit/type/user_spec.rb +1 -1
  128. data/spec/unit/util/autoload_spec.rb +2 -1
  129. data/spec/unit/util/log/destinations_spec.rb +1 -29
  130. data/spec/unit/util/package/version/range_spec.rb +22 -1
  131. data/tasks/manpages.rake +5 -35
  132. metadata +10 -4
@@ -176,6 +176,19 @@ describe Puppet::Type.type(:package).provider(:zypper) do
176
176
  @provider.install
177
177
  end
178
178
 
179
+ it "should install the package with --no-gpg-checks" do
180
+ allow(@resource).to receive(:[]).with(:name).and_return("php5")
181
+ allow(@resource).to receive(:[]).with(:install_options).and_return(['--no-gpg-checks', {'-p' => '/vagrant/files/localrepo/'}])
182
+ allow(@resource).to receive(:should).with(:ensure).and_return("5.4.10-4.5.6")
183
+ allow(@resource).to receive(:allow_virtual?).and_return(false)
184
+ allow(@provider).to receive(:zypper_version).and_return("1.2.8")
185
+
186
+ expect(@provider).to receive(:zypper).with('--quiet', '--no-gpg-checks', :install,
187
+ '--auto-agree-with-licenses', '--no-confirm', '-p=/vagrant/files/localrepo/', 'php5-5.4.10-4.5.6')
188
+ expect(@provider).to receive(:query).and_return("php5 0 5.4.10 4.5.6 x86_64")
189
+ @provider.install
190
+ end
191
+
179
192
  it "should install package with hash install options" do
180
193
  allow(@resource).to receive(:[]).with(:name).and_return('vim')
181
194
  allow(@resource).to receive(:[]).with(:install_options).and_return([{ '--a' => 'foo', '--b' => '"quoted bar"' }])
@@ -226,4 +239,75 @@ describe Puppet::Type.type(:package).provider(:zypper) do
226
239
  @provider.uninstall
227
240
  end
228
241
  end
242
+
243
+ context 'when installing with VersionRange' do
244
+ let(:search_output) { File.read(my_fixture('zypper-search-uninstalled.out')) }
245
+
246
+ before(:each) do
247
+ allow(@resource).to receive(:[]).with(:name).and_return('vim')
248
+ allow(@resource).to receive(:allow_virtual?).and_return(false)
249
+ allow(@provider).to receive(:zypper_version).and_return('1.0.2')
250
+
251
+ expect(@provider).to receive(:zypper).with('search', '--match-exact', '--type', 'package', '--uninstalled-only', '-s', 'vim')
252
+ .and_return(search_output)
253
+ end
254
+
255
+ it 'does install the package if version is available' do
256
+ expect(@resource).to receive(:should).with(:ensure).and_return('>1.0')
257
+
258
+ expect(@provider).to receive(:zypper).with('--quiet', :install, '--auto-agree-with-licenses', '--no-confirm', 'vim-1.0.20040813-19.9')
259
+ expect(@provider).to receive(:query).and_return('vim 0 1.0.20040813 19.9 x86_64')
260
+
261
+ @provider.install
262
+ end
263
+
264
+ it 'does consider range as version if version in range is not available' do
265
+ allow(@resource).to receive(:should).with(:ensure).and_return('>2.0')
266
+
267
+ expect(@provider).to receive(:zypper).with('--quiet', :install, '--auto-agree-with-licenses', '--no-confirm', 'vim->2.0')
268
+ .and_raise(Puppet::ExecutionFailure.new('My Error'))
269
+
270
+ expect { @provider.install }.to raise_error(Puppet::ExecutionFailure, 'My Error')
271
+ end
272
+ end
273
+
274
+ describe 'insync?' do
275
+ subject { @provider.insync?('1.19-2') }
276
+
277
+ context 'when versions are matching' do
278
+ before { allow(@resource).to receive(:[]).with(:ensure).and_return('1.19-2') }
279
+
280
+ it { is_expected.to be true }
281
+ end
282
+
283
+ context 'when version are not matching' do
284
+ before { allow(@resource).to receive(:[]).with(:ensure).and_return('1.19-3') }
285
+
286
+ it { is_expected.to be false }
287
+ end
288
+
289
+ context 'when version is in gt range' do
290
+ before { allow(@resource).to receive(:[]).with(:ensure).and_return('>1.19-0') }
291
+
292
+ it { is_expected.to be true }
293
+ end
294
+
295
+ context 'when version is not in gt range' do
296
+ before { allow(@resource).to receive(:[]).with(:ensure).and_return('>1.19-2') }
297
+
298
+ it { is_expected.to be false }
299
+ end
300
+
301
+ context 'when version is in min-max range' do
302
+ before { allow(@resource).to receive(:[]).with(:ensure).and_return('>1.19-0 <1.19-3') }
303
+
304
+ it { is_expected.to be true }
305
+ end
306
+
307
+ context 'when version is not in min-max range' do
308
+ before { allow(@resource).to receive(:[]).with(:ensure).and_return('>1.19-0 <1.19-2') }
309
+
310
+ it { is_expected.to be false }
311
+ end
312
+ end
229
313
  end
@@ -150,6 +150,7 @@ describe 'Puppet::Type::Service::Provider::Init', unless: Puppet::Util::Platform
150
150
 
151
151
  describe "if the init script is present" do
152
152
  before :each do
153
+ allow(File).to receive(:directory?).and_call_original
153
154
  allow(File).to receive(:directory?).with("/service/path").and_return(true)
154
155
  allow(File).to receive(:directory?).with("/alt/service/path").and_return(true)
155
156
  allow(Puppet::FileSystem).to receive(:exist?).with("/service/path/myservice").and_return(true)
@@ -12,6 +12,15 @@ describe 'Puppet::Type::Service::Provider::Openbsd',
12
12
  allow(FileTest).to receive(:executable?).with('/usr/sbin/rcctl').and_return(true)
13
13
  end
14
14
 
15
+ # `execute` and `texecute` start a new process, consequently setting $CHILD_STATUS to a Process::Status instance,
16
+ # but because they are mocked, an external process is never executed and $CHILD_STATUS remain nil.
17
+ # In order to execute some parts of the code under test and to mock $CHILD_STATUS, we need this variable to be a
18
+ # Process::Status instance. We can achieve this by starting a process that does nothing (exit 0). By doing this,
19
+ # $CHILD_STATUS will be initialised with a instance of Process::Status and we will be able to mock it.
20
+ before(:all) do
21
+ `exit 0`
22
+ end
23
+
15
24
  context "#instances" do
16
25
  it "should have an instances method" do
17
26
  expect(provider_class).to respond_to :instances
@@ -28,6 +28,7 @@ describe 'Puppet::Type::Service::Provider::Openwrt',
28
28
  allow(FileTest).to receive(:executable?).with('/etc/rc.common').and_return(true)
29
29
 
30
30
  # All OpenWrt tests operate on the init script directly. It must exist.
31
+ allow(File).to receive(:directory?).and_call_original
31
32
  allow(File).to receive(:directory?).with('/etc/init.d').and_return(true)
32
33
 
33
34
  allow(Puppet::FileSystem).to receive(:exist?).with('/etc/init.d/myservice').and_return(true)
@@ -4,6 +4,15 @@ describe 'Puppet::Type::Service::Provider::Redhat',
4
4
  if: Puppet.features.posix? && !Puppet::Util::Platform.jruby?do
5
5
  let(:provider_class) { Puppet::Type.type(:service).provider(:redhat) }
6
6
 
7
+ # `execute` and `texecute` start a new process, consequently setting $CHILD_STATUS to a Process::Status instance,
8
+ # but because they are mocked, an external process is never executed and $CHILD_STATUS remain nil.
9
+ # In order to execute some parts of the code under test and to mock $CHILD_STATUS, we need this variable to be a
10
+ # Process::Status instance. We can achieve this by starting a process that does nothing (exit 0). By doing this,
11
+ # $CHILD_STATUS will be initialised with a instance of Process::Status and we will be able to mock it.
12
+ before(:all) do
13
+ `exit 0`
14
+ end
15
+
7
16
  before :each do
8
17
  @class = Puppet::Type.type(:service).provider(:redhat)
9
18
  @resource = double('resource')
@@ -13,6 +13,15 @@ describe 'Puppet::Type::Service::Provider::Systemd', unless: Puppet::Util::Platf
13
13
  allow(provider_class).to receive(:which).with('systemctl').and_return('/bin/systemctl')
14
14
  end
15
15
 
16
+ # `execute` and `texecute` start a new process, consequently setting $CHILD_STATUS to a Process::Status instance,
17
+ # but because they are mocked, an external process is never executed and $CHILD_STATUS remain nil.
18
+ # In order to execute some parts of the code under test and to mock $CHILD_STATUS, we need this variable to be a
19
+ # Process::Status instance. We can achieve this by starting a process that does nothing (exit 0). By doing this,
20
+ # $CHILD_STATUS will be initialised with a instance of Process::Status and we will be able to mock it.
21
+ before(:all) do
22
+ `exit 0`
23
+ end
24
+
16
25
  let :provider do
17
26
  provider_class.new(:name => 'sshd.service')
18
27
  end
@@ -190,6 +199,7 @@ describe 'Puppet::Type::Service::Provider::Systemd', unless: Puppet::Util::Platf
190
199
  apparmor.service
191
200
  umountnfs.service
192
201
  urandom.service
202
+ brandbot.service
193
203
  })
194
204
  end
195
205
 
@@ -198,7 +208,7 @@ describe 'Puppet::Type::Service::Provider::Systemd', unless: Puppet::Util::Platf
198
208
  expect(Puppet).to receive(:debug).with("apparmor.service marked as bad by `systemctl`. It is recommended to be further checked.")
199
209
  provider_class.instances
200
210
  end
201
- end
211
+ end
202
212
 
203
213
  describe "#start" do
204
214
  it "should use the supplied start command if specified" do
@@ -278,43 +288,43 @@ Jun 14 21:43:23 foo.example.com systemd[1]: sshd.service lacks both ExecStart= a
278
288
  describe "#enabled?" do
279
289
  it "should return :true if the service is enabled" do
280
290
  provider = provider_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service'))
281
- expect(provider).to receive(:execute).with(['/bin/systemctl','is-enabled', '--', 'sshd.service'], :failonfail => false).and_return("enabled\n")
282
- allow($CHILD_STATUS).to receive(:exitstatus).and_return(0)
291
+ expect(provider).to receive(:execute).with(['/bin/systemctl','is-enabled', '--', 'sshd.service'], :failonfail => false).
292
+ and_return(Puppet::Util::Execution::ProcessOutput.new("enabled\n", 0))
283
293
  expect(provider.enabled?).to eq(:true)
284
294
  end
285
295
 
286
296
  it "should return :true if the service is static" do
287
297
  provider = provider_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service'))
288
- expect(provider).to receive(:execute).with(['/bin/systemctl','is-enabled','--', 'sshd.service'], :failonfail => false).and_return("static\n")
289
- allow($CHILD_STATUS).to receive(:exitstatus).and_return(0)
298
+ expect(provider).to receive(:execute).with(['/bin/systemctl','is-enabled','--', 'sshd.service'], :failonfail => false).
299
+ and_return(Puppet::Util::Execution::ProcessOutput.new("static\n", 0))
290
300
  expect(provider.enabled?).to eq(:true)
291
301
  end
292
302
 
293
303
  it "should return :false if the service is disabled" do
294
304
  provider = provider_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service'))
295
- expect(provider).to receive(:execute).with(['/bin/systemctl','is-enabled', '--', 'sshd.service'], :failonfail => false).and_return("disabled\n")
296
- allow($CHILD_STATUS).to receive(:exitstatus).and_return(1)
305
+ expect(provider).to receive(:execute).with(['/bin/systemctl','is-enabled', '--', 'sshd.service'], :failonfail => false).
306
+ and_return(Puppet::Util::Execution::ProcessOutput.new("disabled\n", 1))
297
307
  expect(provider.enabled?).to eq(:false)
298
308
  end
299
309
 
300
310
  it "should return :false if the service is indirect" do
301
311
  provider = provider_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service'))
302
- expect(provider).to receive(:execute).with(['/bin/systemctl','is-enabled', '--', 'sshd.service'], :failonfail => false).and_return("indirect\n")
303
- allow($CHILD_STATUS).to receive(:exitstatus).and_return(0)
312
+ expect(provider).to receive(:execute).with(['/bin/systemctl','is-enabled', '--', 'sshd.service'], :failonfail => false).
313
+ and_return(Puppet::Util::Execution::ProcessOutput.new("indirect\n", 0))
304
314
  expect(provider.enabled?).to eq(:false)
305
315
  end
306
316
 
307
317
  it "should return :false if the service is masked and the resource is attempting to be disabled" do
308
318
  provider = provider_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service', :enable => false))
309
- expect(provider).to receive(:execute).with(['/bin/systemctl','is-enabled', '--', 'sshd.service'], :failonfail => false).and_return("masked\n")
310
- allow($CHILD_STATUS).to receive(:exitstatus).and_return(1)
319
+ expect(provider).to receive(:execute).with(['/bin/systemctl','is-enabled', '--', 'sshd.service'], :failonfail => false).
320
+ and_return(Puppet::Util::Execution::ProcessOutput.new("masked\n", 1))
311
321
  expect(provider.enabled?).to eq(:false)
312
322
  end
313
323
 
314
324
  it "should return :mask if the service is masked and the resource is attempting to be masked" do
315
325
  provider = provider_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service', :enable => 'mask'))
316
- expect(provider).to receive(:execute).with(['/bin/systemctl','is-enabled', '--', 'sshd.service'], :failonfail => false).and_return("masked\n")
317
- allow($CHILD_STATUS).to receive(:exitstatus).and_return(1)
326
+ expect(provider).to receive(:execute).with(['/bin/systemctl','is-enabled', '--', 'sshd.service'], :failonfail => false).
327
+ and_return(Puppet::Util::Execution::ProcessOutput.new("masked\n", 1))
318
328
  expect(provider.enabled?).to eq(:mask)
319
329
  end
320
330
  end
@@ -437,6 +447,67 @@ Jun 14 21:43:23 foo.example.com systemd[1]: sshd.service lacks both ExecStart= a
437
447
  end
438
448
  end
439
449
 
450
+ describe "#insync_enabled?" do
451
+ let(:provider) do
452
+ provider_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service', :enable => false))
453
+ end
454
+
455
+ before do
456
+ allow(provider).to receive(:cached_enabled?).and_return({ output: service_state, exitcode: 0 })
457
+ end
458
+
459
+ context 'when service state is static' do
460
+ let(:service_state) { 'static' }
461
+
462
+ it 'is always enabled_insync even if current value is the same as expected' do
463
+ expect(provider).to be_enabled_insync(:false)
464
+ end
465
+
466
+ it 'is always enabled_insync even if current value is not the same as expected' do
467
+ expect(provider).to be_enabled_insync(:true)
468
+ end
469
+
470
+ it 'logs a debug messsage' do
471
+ expect(Puppet).to receive(:debug).with("Unable to enable or disable static service sshd.service")
472
+ provider.enabled_insync?(:true)
473
+ end
474
+ end
475
+
476
+ context 'when service state is indirect' do
477
+ let(:service_state) { 'indirect' }
478
+
479
+ it 'is always enabled_insync even if current value is the same as expected' do
480
+ expect(provider).to be_enabled_insync(:false)
481
+ end
482
+
483
+ it 'is always enabled_insync even if current value is not the same as expected' do
484
+ expect(provider).to be_enabled_insync(:true)
485
+ end
486
+
487
+ it 'logs a debug messsage' do
488
+ expect(Puppet).to receive(:debug).with("Service sshd.service is in 'indirect' state and cannot be enabled/disabled")
489
+ provider.enabled_insync?(:true)
490
+ end
491
+ end
492
+
493
+ context 'when service state is enabled' do
494
+ let(:service_state) { 'enabled' }
495
+
496
+ it 'is enabled_insync if current value is the same as expected' do
497
+ expect(provider).to be_enabled_insync(:false)
498
+ end
499
+
500
+ it 'is not enabled_insync if current value is not the same as expected' do
501
+ expect(provider).not_to be_enabled_insync(:true)
502
+ end
503
+
504
+ it 'logs no debug messsage' do
505
+ expect(Puppet).not_to receive(:debug)
506
+ provider.enabled_insync?(:true)
507
+ end
508
+ end
509
+ end
510
+
440
511
  describe "#get_start_link_count" do
441
512
  it "should strip the '.service' from the search if present in the resource name" do
442
513
  provider = provider_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service'))
@@ -315,6 +315,14 @@ describe Puppet::Type.type(:user).provider(:useradd) do
315
315
  expect(provider).to receive(:execute).with(['/usr/sbin/usermod', '-e', '', 'myuser'], hash_including(custom_environment: {}))
316
316
  provider.expiry = :absent
317
317
  end
318
+
319
+ it "should use -e with -1 when the expiry property is removed on SLES11" do
320
+ allow(Facter).to receive(:value).with(:operatingsystem).and_return('SLES')
321
+ allow(Facter).to receive(:value).with(:operatingsystemmajrelease).and_return('11')
322
+ resource[:expiry] = :absent
323
+ expect(provider).to receive(:execute).with(['/usr/sbin/usermod', '-e', -1, 'myuser'], hash_including(custom_environment: {}))
324
+ provider.expiry = :absent
325
+ end
318
326
  end
319
327
 
320
328
  describe "#comment" do
@@ -533,6 +533,19 @@ describe 'Puppet Pal' do
533
533
  end.to raise_error(Puppet::Error, /Could not find resource 'Bar\[nope\]'/)
534
534
  end
535
535
 
536
+ it 'an "evaluate" followed by "evaluate_ast_node" will correctly parse a node definition' do
537
+ Puppet[:node_name_value] = 'testing_node'
538
+ result = Puppet::Pal.in_tmp_environment('pal_env', modulepath: modulepath, facts: node_facts) do | ctx|
539
+ ctx.with_catalog_compiler do |c|
540
+ c.evaluate(c.parse_string("node 'testing_node' { notify {'PASSED': } }"))
541
+ c.evaluate_ast_node
542
+ c.compile_additions
543
+ c.with_json_encoding() {|encoder| encoder.encode }
544
+ end
545
+ end
546
+ parsed = JSON.parse(result)
547
+ expect(parsed['resources']).to include(include('type' => 'Notify'))
548
+ end
536
549
  end
537
550
  end
538
551
 
@@ -632,6 +645,25 @@ describe 'Puppet Pal' do
632
645
  end
633
646
  RUBY
634
647
  }
648
+ },
649
+ 'datatypes' => {
650
+ 'mytype.rb' => <<-RUBY.unindent,
651
+ Puppet::DataTypes.create_type('Mytype') do
652
+ interface <<-PUPPET
653
+ attributes => {
654
+ name => { type => String },
655
+ year_of_birth => { type => Integer },
656
+ age => { type => Integer, kind => derived },
657
+ }
658
+ PUPPET
659
+
660
+ implementation do
661
+ def age
662
+ DateTime.now.year - @year_of_birth
663
+ end
664
+ end
665
+ end
666
+ RUBY
635
667
  }
636
668
  }
637
669
  }
@@ -749,6 +781,17 @@ describe 'Puppet Pal' do
749
781
  end
750
782
  end
751
783
 
784
+ context 'datatypes are supported such that' do
785
+ it 'datatypes defined as pcore in a module are deserialized' do
786
+ testing_env_dir
787
+ vars = {"bobs_age"=>{"__ptype"=>"Mytype", "name"=>"Bob", "year_of_birth"=>1984}}
788
+ result = Puppet::Pal.in_environment('pal_env', envpath: environments_dir, facts: node_facts, variables: vars) do |ctx|
789
+ ctx.with_catalog_compiler {|c| c.evaluate_string("$bobs_age.age") }
790
+ end
791
+ expect(result).to eq(DateTime.now.year - 1984)
792
+ end
793
+ end
794
+
752
795
  context 'configured as an existing given environment directory such that' do
753
796
  it 'modules in it are available from its "modules" directory' do
754
797
  result = Puppet::Pal.in_environment('pal_env', env_dir: testing_env_dir, facts: node_facts) do |ctx|
@@ -83,4 +83,37 @@ describe Puppet do
83
83
  expect(Puppet.settings).to eq(new_settings)
84
84
  end
85
85
  end
86
+
87
+ context 'when registering implementations' do
88
+ it 'does not register an implementation by default' do
89
+ Puppet.initialize_settings
90
+
91
+ expect(Puppet.runtime[:http]).to be_an_instance_of(Puppet::HTTP::Client)
92
+ end
93
+
94
+ it 'allows an implementation to be registered' do
95
+ impl = double('http')
96
+ Puppet.initialize_settings([], true, true, http: impl)
97
+
98
+
99
+ expect(Puppet.runtime[:http]).to eq(impl)
100
+ end
101
+ end
102
+
103
+ context "initializing $LOAD_PATH" do
104
+ it "should add libdir and module paths to the load path" do
105
+ libdir = tmpdir('libdir_test')
106
+ vendor_dir = tmpdir('vendor_modules')
107
+ module_libdir = File.join(vendor_dir, 'amodule_core', 'lib')
108
+ FileUtils.mkdir_p(module_libdir)
109
+
110
+ Puppet[:libdir] = libdir
111
+ Puppet[:vendormoduledir] = vendor_dir
112
+ Puppet.initialize_settings
113
+
114
+ expect($LOAD_PATH).to include(libdir)
115
+ expect($LOAD_PATH).to include(module_libdir)
116
+ end
117
+
118
+ end
86
119
  end
@@ -64,7 +64,7 @@ describe Puppet::Reports.report(:http) do
64
64
  it "passes metric_id options" do
65
65
  stub_request(:post, url)
66
66
 
67
- expect(Puppet.runtime['http']).to receive(:post).with(anything, anything, hash_including(options: hash_including(metric_id: [:puppet, :report, :http]))).and_call_original
67
+ expect(Puppet.runtime[:http]).to receive(:post).with(anything, anything, hash_including(options: hash_including(metric_id: [:puppet, :report, :http]))).and_call_original
68
68
 
69
69
  subject.process
70
70
  end
@@ -228,13 +228,6 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
228
228
  expect(File).to_not be_exist(Puppet[:ssl_lockfile])
229
229
  end
230
230
 
231
- it 'raises an exception when locking fails' do
232
- allow(lockfile).to receive(:lock).and_return(false)
233
- expect {
234
- machine.ensure_ca_certificates
235
- }.to raise_error(Puppet::Error, /Another puppet instance is already running; exiting/)
236
- end
237
-
238
231
  it 'acquires an empty lockfile' do
239
232
  Puppet::FileSystem.touch(Puppet[:ssl_lockfile])
240
233
 
@@ -262,6 +255,57 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
262
255
  machine = described_class.new(cert_provider: cert_provider, ssl_provider: ssl_provider)
263
256
  machine.ensure_ca_certificates
264
257
  end
258
+
259
+ context 'and another puppet process is running' do
260
+ let(:now) { Time.now }
261
+ let(:future) { now + (5 * 60)} # 5 mins in the future
262
+
263
+ before :each do
264
+ allow(lockfile).to receive(:lock).and_return(false)
265
+ end
266
+
267
+ it 'raises a puppet exception' do
268
+ expect {
269
+ machine.ensure_ca_certificates
270
+ }.to raise_error(Puppet::Error, /Another puppet instance is already running and the waitforlock setting is set to 0; exiting/)
271
+ end
272
+
273
+ it 'sleeps and retries successfully' do
274
+ machine = described_class.new(lockfile: lockfile, cert_provider: cert_provider, waitforlock: 1, maxwaitforlock: 10)
275
+ allow(cert_provider).to receive(:load_cacerts).and_return(cacerts)
276
+ allow(cert_provider).to receive(:load_crls).and_return(crls)
277
+ allow(Time).to receive(:now).and_return(now, future)
278
+
279
+ expect(Kernel).to receive(:sleep).with(1)
280
+ expect(Puppet).to receive(:info).with("Another puppet instance is already running; waiting for it to finish")
281
+ expect(Puppet).to receive(:info).with("Will try again in 1 seconds.")
282
+
283
+ allow(lockfile).to receive(:lock).and_return(false, true)
284
+
285
+ expect(machine.ensure_ca_certificates).to be_an_instance_of(Puppet::SSL::SSLContext)
286
+ end
287
+
288
+ it 'sleeps and retries unsuccessfully until the deadline is exceeded' do
289
+ machine = described_class.new(lockfile: lockfile, waitforlock: 1, maxwaitforlock: 10)
290
+ allow(Time).to receive(:now).and_return(now, future)
291
+
292
+ expect(Kernel).to receive(:sleep).with(1)
293
+ expect(Puppet).to receive(:info).with("Another puppet instance is already running; waiting for it to finish")
294
+ expect(Puppet).to receive(:info).with("Will try again in 1 seconds.")
295
+
296
+ allow(lockfile).to receive(:lock).and_return(false)
297
+ expect {
298
+ machine.ensure_ca_certificates
299
+ }.to raise_error(Puppet::Error, /Another puppet instance is already running and the maxwaitforlock timeout has been exceeded; exiting/)
300
+ end
301
+
302
+ it 'defaults the waitlock deadline to 60 seconds' do
303
+ allow(Time).to receive(:now).and_return(now)
304
+
305
+ machine = described_class.new
306
+ expect(machine.waitlock_deadline).to eq(now.to_i + 60)
307
+ end
308
+ end
265
309
  end
266
310
 
267
311
  context 'NeedCACerts' do
@@ -882,7 +926,7 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
882
926
  machine = described_class.new(waitforcert: 15)
883
927
 
884
928
  state = Puppet::SSL::StateMachine::Wait.new(machine)
885
- expect(Puppet.runtime['http'].pool).to receive(:close).and_call_original
929
+ expect(Puppet.runtime[:http].pool).to receive(:close).and_call_original
886
930
  expect(Kernel).to receive(:sleep).with(15).ordered
887
931
 
888
932
  state.next_state