puppet 6.11.1 → 6.12.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 (126) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +1 -1
  3. data/Gemfile +1 -0
  4. data/Gemfile.lock +16 -16
  5. data/README.md +1 -1
  6. data/ext/build_defaults.yaml +1 -0
  7. data/ext/windows/service/daemon.rb +22 -17
  8. data/lib/puppet/concurrent.rb +2 -0
  9. data/lib/puppet/concurrent/lock.rb +16 -0
  10. data/lib/puppet/concurrent/synchronized.rb +15 -0
  11. data/lib/puppet/concurrent/thread_local_singleton.rb +14 -0
  12. data/lib/puppet/configurer.rb +45 -31
  13. data/lib/puppet/defaults.rb +42 -3
  14. data/lib/puppet/environments.rb +3 -0
  15. data/lib/puppet/error.rb +9 -1
  16. data/lib/puppet/forge.rb +3 -3
  17. data/lib/puppet/forge/errors.rb +2 -2
  18. data/lib/puppet/forge/repository.rb +30 -86
  19. data/lib/puppet/functions/camelcase.rb +2 -2
  20. data/lib/puppet/functions/epp.rb +4 -4
  21. data/lib/puppet/functions/find_file.rb +9 -9
  22. data/lib/puppet/functions/find_template.rb +63 -0
  23. data/lib/puppet/functions/inline_epp.rb +5 -5
  24. data/lib/puppet/http.rb +2 -0
  25. data/lib/puppet/http/client.rb +89 -17
  26. data/lib/puppet/http/resolver.rb +14 -1
  27. data/lib/puppet/http/resolver/server_list.rb +38 -0
  28. data/lib/puppet/http/resolver/settings.rb +3 -2
  29. data/lib/puppet/http/resolver/srv.rb +10 -4
  30. data/lib/puppet/http/service.rb +32 -0
  31. data/lib/puppet/http/service/ca.rb +11 -10
  32. data/lib/puppet/http/service/report.rb +40 -0
  33. data/lib/puppet/http/session.rb +11 -32
  34. data/lib/puppet/network/http/base_pool.rb +13 -0
  35. data/lib/puppet/node/environment.rb +13 -7
  36. data/lib/puppet/pal/pal_impl.rb +5 -0
  37. data/lib/puppet/parser/functions/epp.rb +3 -3
  38. data/lib/puppet/parser/functions/inline_epp.rb +5 -5
  39. data/lib/puppet/pops/evaluator/runtime3_support.rb +1 -1
  40. data/lib/puppet/pops/lookup/invocation.rb +10 -3
  41. data/lib/puppet/pops/model/pn_transformer.rb +5 -9
  42. data/lib/puppet/pops/parser/evaluating_parser.rb +3 -4
  43. data/lib/puppet/pops/serialization/json_path.rb +3 -3
  44. data/lib/puppet/pops/time/timespan.rb +3 -5
  45. data/lib/puppet/pops/types/string_converter.rb +6 -9
  46. data/lib/puppet/pops/types/type_calculator.rb +6 -10
  47. data/lib/puppet/pops/types/type_formatter.rb +9 -11
  48. data/lib/puppet/pops/types/type_parser.rb +3 -3
  49. data/lib/puppet/provider/package/portage.rb +3 -3
  50. data/lib/puppet/provider/package_targetable.rb +5 -4
  51. data/lib/puppet/provider/service/systemd.rb +1 -1
  52. data/lib/puppet/provider/user/hpux.rb +1 -1
  53. data/lib/puppet/runtime.rb +1 -0
  54. data/lib/puppet/ssl/ssl_provider.rb +20 -0
  55. data/lib/puppet/transaction.rb +33 -11
  56. data/lib/puppet/type.rb +1 -1
  57. data/lib/puppet/type/file/data_sync.rb +5 -1
  58. data/lib/puppet/type/group.rb +3 -2
  59. data/lib/puppet/type/user.rb +3 -2
  60. data/lib/puppet/util.rb +34 -11
  61. data/lib/puppet/util/logging.rb +30 -18
  62. data/lib/puppet/util/windows/adsi.rb +48 -18
  63. data/lib/puppet/version.rb +1 -1
  64. data/lib/puppet/x509/cert_provider.rb +9 -5
  65. data/locales/puppet.pot +155 -141
  66. data/man/man5/puppet.conf.5 +33 -3
  67. data/man/man8/puppet-agent.8 +1 -1
  68. data/man/man8/puppet-apply.8 +1 -1
  69. data/man/man8/puppet-catalog.8 +1 -1
  70. data/man/man8/puppet-config.8 +1 -1
  71. data/man/man8/puppet-describe.8 +1 -1
  72. data/man/man8/puppet-device.8 +1 -1
  73. data/man/man8/puppet-doc.8 +1 -1
  74. data/man/man8/puppet-epp.8 +1 -1
  75. data/man/man8/puppet-facts.8 +1 -1
  76. data/man/man8/puppet-filebucket.8 +1 -1
  77. data/man/man8/puppet-generate.8 +1 -1
  78. data/man/man8/puppet-help.8 +1 -1
  79. data/man/man8/puppet-key.8 +1 -1
  80. data/man/man8/puppet-lookup.8 +1 -1
  81. data/man/man8/puppet-man.8 +1 -1
  82. data/man/man8/puppet-module.8 +1 -1
  83. data/man/man8/puppet-node.8 +1 -1
  84. data/man/man8/puppet-parser.8 +1 -1
  85. data/man/man8/puppet-plugin.8 +1 -1
  86. data/man/man8/puppet-report.8 +1 -1
  87. data/man/man8/puppet-resource.8 +1 -1
  88. data/man/man8/puppet-script.8 +1 -1
  89. data/man/man8/puppet-ssl.8 +1 -1
  90. data/man/man8/puppet-status.8 +1 -1
  91. data/man/man8/puppet.8 +2 -2
  92. data/spec/fixtures/unit/forge/bacula.json +76 -0
  93. data/spec/integration/http/client_spec.rb +144 -0
  94. data/spec/integration/module_tool/forge_spec.rb +64 -0
  95. data/spec/lib/puppet_spec/https.rb +5 -3
  96. data/spec/spec_helper.rb +6 -2
  97. data/spec/unit/concurrent/lock_spec.rb +29 -0
  98. data/spec/unit/configurer_spec.rb +394 -399
  99. data/spec/unit/defaults_spec.rb +15 -4
  100. data/spec/unit/forge/errors_spec.rb +1 -1
  101. data/spec/unit/forge/forge_spec.rb +12 -54
  102. data/spec/unit/forge/module_release_spec.rb +19 -6
  103. data/spec/unit/forge/repository_spec.rb +63 -157
  104. data/spec/unit/forge_spec.rb +46 -116
  105. data/spec/unit/functions/find_template_spec.rb +69 -0
  106. data/spec/unit/http/client_spec.rb +138 -6
  107. data/spec/unit/http/resolver_spec.rb +49 -12
  108. data/spec/unit/http/service/ca_spec.rb +56 -5
  109. data/spec/unit/http/service/report_spec.rb +100 -0
  110. data/spec/unit/http/service_spec.rb +20 -0
  111. data/spec/unit/http/session_spec.rb +53 -18
  112. data/spec/unit/network/http/connection_spec.rb +0 -1
  113. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +8 -3
  114. data/spec/unit/provider/package/portage_spec.rb +4 -4
  115. data/spec/unit/provider/package_targetable_spec.rb +60 -0
  116. data/spec/unit/provider/user/hpux_spec.rb +2 -2
  117. data/spec/unit/ssl/ssl_provider_spec.rb +71 -0
  118. data/spec/unit/transaction_spec.rb +46 -0
  119. data/spec/unit/type/file/content_spec.rb +9 -3
  120. data/spec/unit/util/log_spec.rb +0 -138
  121. data/spec/unit/util/logging_spec.rb +200 -0
  122. data/spec/unit/util/windows/adsi_spec.rb +51 -0
  123. data/spec/unit/x509/cert_provider_spec.rb +24 -4
  124. data/tasks/manpages.rake +1 -0
  125. metadata +24 -5
  126. data/spec/lib/puppet_spec/validators.rb +0 -37
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+ require 'puppet'
3
+ require 'puppet/provider/package_targetable'
4
+ require 'puppet/provider/package/gem'
5
+
6
+ describe Puppet::Provider::Package::Targetable do
7
+ let(:provider) { Puppet::Type.type(:package).provider(:gem) }
8
+ let(:command) { '/opt/bin/gem' }
9
+
10
+ describe "when prefetching" do
11
+ context "with a package without a command attribute" do
12
+ let(:resource) { Puppet::Type.type(:package).new(:name => 'noo', :provider => 'gem', :ensure => :present) }
13
+ let(:catalog) { Puppet::Resource::Catalog.new }
14
+ let(:instance) { provider.new(resource) }
15
+ let(:packages) { { 'noo' => resource } }
16
+
17
+ it "should pass a command to the instances method of the provider" do
18
+ catalog.add_resource(resource)
19
+ expect(provider).to receive(:instances).with(nil).and_return([instance])
20
+ expect(provider.prefetch(packages)).to eq([nil]) # prefetch arbitrarily returns the array of commands for a provider in the catalog
21
+ end
22
+ end
23
+
24
+ context "with a package with a command attribute" do
25
+ let(:resource) { Puppet::Type.type(:package).new(:name => 'noo', :provider => 'gem', :ensure => :present) }
26
+ let(:resource_targeted) { Puppet::Type.type(:package).new(:name => 'yes', :provider => 'gem', :command => command, :ensure => :present) }
27
+ let(:catalog) { Puppet::Resource::Catalog.new }
28
+ let(:instance) { provider.new(resource) }
29
+ let(:instance_targeted) { provider.new(resource_targeted) }
30
+ let(:packages) { { 'noo' => resource, 'yes' => resource_targeted } }
31
+
32
+ it "should pass the command to the instances method of the provider" do
33
+ catalog.add_resource(resource)
34
+ catalog.add_resource(resource_targeted)
35
+ expect(provider).to receive(:instances).with(nil).and_return([instance])
36
+ expect(provider).to receive(:instances).with(command).and_return([instance_targeted]).once
37
+ expect(provider.prefetch(packages)).to eq([nil, command]) # prefetch arbitrarily returns the array of commands for a provider in the catalog
38
+ end
39
+ end
40
+ end
41
+
42
+ describe "when validating a command" do
43
+ context "with no command" do
44
+ it "report not functional" do
45
+ expect { provider.validate_command(nil) }.to raise_error(Puppet::Error, "Provider gem package command is not functional on this host")
46
+ end
47
+ end
48
+ context "with a missing command" do
49
+ it "report does not exist" do
50
+ expect { provider.validate_command(command) }.to raise_error(Puppet::Error, "Provider gem package command '#{command}' does not exist on this host")
51
+ end
52
+ end
53
+ context "with an existing command" do
54
+ it "validates" do
55
+ allow(File).to receive(:file?).with(command).and_return(true)
56
+ expect { provider.validate_command(command) }.not_to raise_error
57
+ end
58
+ end
59
+ end
60
+ end
@@ -58,14 +58,14 @@ describe Puppet::Type.type(:user).provider(:hpuxuseradd),
58
58
  it "should add modprpw to modifycmd if Trusted System" do
59
59
  allow(resource).to receive(:allowdupe?).and_return(true)
60
60
  expect(provider).to receive(:exec_getprpw).with('root','-m uid').and_return('uid=0')
61
- expect(provider).to receive(:execute).with(['/usr/sam/lbin/usermod.sam', '-u', 1000, '-o', 'testuser', '-F', ';', '/usr/lbin/modprpw', '-v', '-l', 'testuser'], hash_including(custom_environment: {}))
61
+ expect(provider).to receive(:execute).with(['/usr/sam/lbin/usermod.sam', '-F', '-u', 1000, '-o', 'testuser', ';', '/usr/lbin/modprpw', '-v', '-l', 'testuser'], hash_including(custom_environment: {}))
62
62
  provider.uid = 1000
63
63
  end
64
64
 
65
65
  it "should not add modprpw if not Trusted System" do
66
66
  allow(resource).to receive(:allowdupe?).and_return(true)
67
67
  expect(provider).to receive(:exec_getprpw).with('root','-m uid').and_return('System is not trusted')
68
- expect(provider).to receive(:execute).with(['/usr/sam/lbin/usermod.sam', '-u', 1000, '-o', 'testuser', '-F'], hash_including(custom_environment: {}))
68
+ expect(provider).to receive(:execute).with(['/usr/sam/lbin/usermod.sam', '-F', '-u', 1000, '-o', 'testuser'], hash_including(custom_environment: {}))
69
69
  provider.uid = 1000
70
70
  end
71
71
  end
@@ -73,6 +73,67 @@ describe Puppet::SSL::SSLProvider do
73
73
  sslctx.verify_peer = false
74
74
  }.to raise_error(/can't modify frozen/)
75
75
  end
76
+
77
+ it 'verifies peer' do
78
+ sslctx = subject.create_root_context(config)
79
+ expect(sslctx.verify_peer).to eq(true)
80
+ end
81
+ end
82
+
83
+ context 'when creating a system ssl context' do
84
+ it 'accepts empty list of CA certs' do
85
+ sslctx = subject.create_system_context(cacerts: [])
86
+ expect(sslctx.cacerts).to eq([])
87
+ end
88
+
89
+ it 'accepts valid root certs' do
90
+ certs = [cert_fixture('ca.pem')]
91
+ sslctx = subject.create_system_context(cacerts: certs)
92
+ expect(sslctx.cacerts).to eq(certs)
93
+ end
94
+
95
+ it 'accepts valid intermediate certs' do
96
+ certs = [cert_fixture('ca.pem'), cert_fixture('intermediate.pem')]
97
+ sslctx = subject.create_system_context(cacerts: certs)
98
+ expect(sslctx.cacerts).to eq(certs)
99
+ end
100
+
101
+ it 'accepts expired CA certs' do
102
+ expired = [cert_fixture('ca.pem'), cert_fixture('intermediate.pem')]
103
+ expired.each { |x509| x509.not_after = Time.at(0) }
104
+
105
+ sslctx = subject.create_system_context(cacerts: expired)
106
+ expect(sslctx.cacerts).to eq(expired)
107
+ end
108
+
109
+ it 'raises if the frozen context is modified' do
110
+ sslctx = subject.create_system_context(cacerts: [])
111
+ expect {
112
+ sslctx.verify_peer = false
113
+ }.to raise_error(/can't modify frozen/)
114
+ end
115
+
116
+ it 'trusts system ca store' do
117
+ expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths)
118
+
119
+ subject.create_system_context(cacerts: [])
120
+ end
121
+
122
+ it 'verifies peer' do
123
+ sslctx = subject.create_system_context(cacerts: [])
124
+ expect(sslctx.verify_peer).to eq(true)
125
+ end
126
+
127
+ it 'disable revocation' do
128
+ sslctx = subject.create_system_context(cacerts: [])
129
+ expect(sslctx.revocation).to eq(false)
130
+ end
131
+
132
+ it 'sets client cert and private key to nil' do
133
+ sslctx = subject.create_system_context(cacerts: [])
134
+ expect(sslctx.client_cert).to be_nil
135
+ expect(sslctx.private_key).to be_nil
136
+ end
76
137
  end
77
138
 
78
139
  context 'when creating an ssl context with crls' do
@@ -99,6 +160,11 @@ describe Puppet::SSL::SSLProvider do
99
160
  sslctx = subject.create_root_context(config.merge(crls: expired))
100
161
  expect(sslctx.crls).to eq(expired)
101
162
  end
163
+
164
+ it 'verifies peer' do
165
+ sslctx = subject.create_root_context(config)
166
+ expect(sslctx.verify_peer).to eq(true)
167
+ end
102
168
  end
103
169
 
104
170
  context 'when creating an ssl context with client certs' do
@@ -345,6 +411,11 @@ describe Puppet::SSL::SSLProvider do
345
411
  sslctx.verify_peer = false
346
412
  }.to raise_error(/can't modify frozen/)
347
413
  end
414
+
415
+ it 'verifies peer' do
416
+ sslctx = subject.create_context(config)
417
+ expect(sslctx.verify_peer).to eq(true)
418
+ end
348
419
  end
349
420
 
350
421
  context 'when loading an ssl context' do
@@ -3,6 +3,7 @@ require 'matchers/include_in_order'
3
3
  require 'puppet_spec/compiler'
4
4
 
5
5
  require 'puppet/transaction'
6
+ require 'puppet/type/exec'
6
7
  require 'puppet/type/notify'
7
8
  require 'fileutils'
8
9
 
@@ -967,6 +968,51 @@ describe Puppet::Transaction do
967
968
  expect(times_send_log_with_skipping_called).to eq(3)
968
969
  end
969
970
  end
971
+
972
+ describe "failed dependency is depended on multiple times" do
973
+ it "notifies and warns the failed class dependency once" do
974
+ Puppet.settings[:merge_dependency_warnings] = true
975
+
976
+ command_string = File.expand_path('/my/command')
977
+ allow(Puppet::Util::Execution).to receive(:execute).with([command_string]).and_raise(Puppet::ExecutionFailure, "Failed")
978
+
979
+ # Exec['exec1'] is outside of a class, so it's warning is not subject to being coalesced.
980
+ times_send_log_with_skipping_called = 0
981
+ allow_any_instance_of(Puppet::Type::Exec).to receive(:send_log) {times_send_log_with_skipping_called += 1; nil}.with(:warning, "Skipping because of failed dependencies")
982
+
983
+ # Class['declared_class'] depends upon Class['required_class'] which contains a resource with a failure.
984
+ times_send_log_with_class_dependency_called = 0
985
+ allow_any_instance_of(Puppet::Type).to receive(:send_log) {times_send_log_with_class_dependency_called += 1; nil}.with(:notice, "Class dependency Exec[exec2] has failures: true")
986
+ times_send_log_with_class_skipping_called = 0
987
+ allow_any_instance_of(Puppet::Type).to receive(:send_log) {times_send_log_with_class_skipping_called += 1; nil}.with(:warning, "Skipping resources in class because of failed class dependencies")
988
+
989
+ apply_compiled_manifest(<<-MANIFEST)
990
+ class required_class {
991
+ exec { 'exec2':
992
+ command => '#{command_string}'
993
+ }
994
+ }
995
+ class declared_class {
996
+ require required_class
997
+ exec { 'exec3':
998
+ command => '#{command_string}'
999
+ }
1000
+ exec { 'exec4':
1001
+ command => '#{command_string}'
1002
+ }
1003
+ }
1004
+ exec { 'exec1':
1005
+ command => '#{command_string}',
1006
+ require => Exec['exec2']
1007
+ }
1008
+ include declared_class
1009
+ MANIFEST
1010
+
1011
+ expect(times_send_log_with_skipping_called).to eq(1)
1012
+ expect(times_send_log_with_class_dependency_called).to eq(1)
1013
+ expect(times_send_log_with_class_skipping_called).to eq(1)
1014
+ end
1015
+ end
970
1016
  end
971
1017
 
972
1018
  describe Puppet::Transaction, " when determining tags" do
@@ -200,15 +200,21 @@ describe Puppet::Type.type(:file).attrclass(:content), :uses_checksums => true d
200
200
  end
201
201
 
202
202
  it "prints the diff" do
203
- expect(content).to receive(:diff).and_return("my diff").once
204
- expect(content).to receive(:debug).with("\nmy diff").once
203
+ expect(content).to receive(:diff).and_return("my diff")
204
+ expect(content).to receive(:debug).with("\nmy diff")
205
+ expect(content).not_to be_safe_insync("other content")
206
+ end
207
+
208
+ it "prints binary file notice if diff is not valid encoding" do
209
+ expect(content).to receive(:diff).and_return("\xc7\xd1\xfc\x84")
210
+ expect(content).to receive(:debug).with(/\nBinary files #{filename} and .* differ/)
205
211
  expect(content).not_to be_safe_insync("other content")
206
212
  end
207
213
 
208
214
  it "redacts the diff when the property is sensitive" do
209
215
  content.sensitive = true
210
216
  expect(content).not_to receive(:diff)
211
- expect(content).to receive(:debug).with("[diff redacted]").once
217
+ expect(content).to receive(:debug).with("[diff redacted]")
212
218
  expect(content).not_to be_safe_insync("other content")
213
219
  end
214
220
  end
@@ -177,144 +177,6 @@ describe Puppet::Util::Log do
177
177
 
178
178
  expect(logs.collect(&:message)).to include("Inner block", "Outer block")
179
179
  end
180
-
181
- it 'includes backtrace for RuntimeError in log message when trace option is passed' do
182
- logs = []
183
- destination = Puppet::Test::LogCollector.new(logs)
184
-
185
- Puppet::Util::Log.newdestination(destination)
186
- Puppet::Util::Log.with_destination(destination) do
187
- begin
188
- raise RuntimeError, 'Oops'
189
- rescue RuntimeError => e
190
- Puppet.log_exception(e, :default, :trace => true)
191
- end
192
- end
193
- expect(logs.size).to eq(1)
194
- log = logs[0]
195
- expect(log.message).to match('/log_spec.rb')
196
- expect(log.backtrace).to be_nil
197
- end
198
-
199
- context "global options" do
200
- around :each do |example|
201
- Puppet[:trace] = true
202
- example.run
203
- Puppet[:trace] = false
204
- end
205
-
206
- it 'includes backtrace for RuntimeError in log message when trace is enabled globally' do
207
- logs = []
208
- destination = Puppet::Test::LogCollector.new(logs)
209
-
210
- Puppet::Util::Log.newdestination(destination)
211
- Puppet::Util::Log.with_destination(destination) do
212
- begin
213
- raise RuntimeError, 'Oops'
214
- rescue RuntimeError => e
215
- Puppet.log_exception(e, :default)
216
- end
217
- end
218
- expect(logs.size).to eq(1)
219
- log = logs[0]
220
- expect(log.message).to match('/log_spec.rb')
221
- expect(log.backtrace).to be_nil
222
- end
223
- end
224
-
225
- it 'excludes backtrace for RuntimeError in log message when trace is disabled' do
226
- logs = []
227
- destination = Puppet::Test::LogCollector.new(logs)
228
-
229
- Puppet::Util::Log.newdestination(destination)
230
- Puppet::Util::Log.with_destination(destination) do
231
- begin
232
- raise RuntimeError, 'Oops'
233
- rescue RuntimeError => e
234
- Puppet.log_exception(e)
235
- end
236
- end
237
- expect(logs.size).to eq(1)
238
- log = logs[0]
239
- expect(log.message).to_not match('/log_spec.rb')
240
- expect(log.backtrace).to be_nil
241
- end
242
-
243
- it "backtrace is Array in 'backtrace' and excluded from 'message' when logging ParseErrorWithIssue with trace enabled" do
244
- logs = []
245
- destination = Puppet::Test::LogCollector.new(logs)
246
-
247
- Puppet::Util::Log.newdestination(destination)
248
- Puppet::Util::Log.with_destination(destination) do
249
- begin
250
- raise Puppet::ParseErrorWithIssue.new('Oops', '/tmp/test.pp', 30, 15, nil, :SYNTAX_ERROR)
251
- rescue RuntimeError => e
252
- Puppet.log_exception(e, :default, :trace => true)
253
- end
254
- end
255
- expect(logs.size).to eq(1)
256
- log = logs[0]
257
- expect(log.message).to_not match('/log_spec.rb')
258
- expect(log.backtrace).to be_a(Array)
259
- end
260
-
261
- it "backtrace is excluded when logging ParseErrorWithIssue with trace disabled" do
262
- logs = []
263
- destination = Puppet::Test::LogCollector.new(logs)
264
-
265
- Puppet::Util::Log.newdestination(destination)
266
- Puppet::Util::Log.with_destination(destination) do
267
- begin
268
- raise Puppet::ParseErrorWithIssue.new('Oops', '/tmp/test.pp', 30, 15, nil, :SYNTAX_ERROR)
269
- rescue RuntimeError => e
270
- Puppet.log_exception(e)
271
- end
272
- end
273
- expect(logs.size).to eq(1)
274
- log = logs[0]
275
- expect(log.message).to_not match('/log_spec.rb')
276
- expect(log.backtrace).to be_nil
277
- end
278
-
279
- it 'includes position details for ParseError in log message' do
280
- logs = []
281
- destination = Puppet::Test::LogCollector.new(logs)
282
-
283
- Puppet::Util::Log.newdestination(destination)
284
- Puppet::Util::Log.with_destination(destination) do
285
- begin
286
- raise Puppet::ParseError.new('Oops', '/tmp/test.pp', 30, 15)
287
- rescue RuntimeError => e
288
- Puppet.log_exception(e)
289
- end
290
- end
291
- expect(logs.size).to eq(1)
292
- log = logs[0]
293
- expect(log.message).to match(/ \(file: \/tmp\/test\.pp, line: 30, column: 15\)/)
294
- expect(log.message).to be(log.to_s)
295
- end
296
-
297
- it 'excludes position details for ParseErrorWithIssue from log message' do
298
- logs = []
299
- destination = Puppet::Test::LogCollector.new(logs)
300
-
301
- Puppet::Util::Log.newdestination(destination)
302
- Puppet::Util::Log.with_destination(destination) do
303
- begin
304
- raise Puppet::ParseErrorWithIssue.new('Oops', '/tmp/test.pp', 30, 15, nil, :SYNTAX_ERROR)
305
- rescue RuntimeError => e
306
- Puppet.log_exception(e)
307
- end
308
- end
309
- expect(logs.size).to eq(1)
310
- log = logs[0]
311
- expect(log.message).to_not match(/ \(file: \/tmp\/test\.pp, line: 30, column: 15\)/)
312
- expect(log.to_s).to match(/ \(file: \/tmp\/test\.pp, line: 30, column: 15\)/)
313
- expect(log.issue_code).to eq(:SYNTAX_ERROR)
314
- expect(log.file).to eq('/tmp/test.pp')
315
- expect(log.line).to eq(30)
316
- expect(log.pos).to eq(15)
317
- end
318
180
  end
319
181
 
320
182
  describe Puppet::Util::Log::DestConsole do
@@ -13,6 +13,39 @@ class LoggingTester
13
13
  include Puppet::Util::Logging
14
14
  end
15
15
 
16
+ class PuppetStackCreator
17
+ def raise_error(exception_class)
18
+ case exception_class
19
+ when Puppet::ParseErrorWithIssue
20
+ raise exception_class.new('Oops', '/tmp/test.pp', 30, 15, nil, :SYNTAX_ERROR)
21
+ when Puppet::ParseError
22
+ raise exception_class.new('Oops', '/tmp/test.pp', 30, 15)
23
+ else
24
+ raise exception_class.new('Oops')
25
+ end
26
+ end
27
+
28
+ def call_raiser(exception_class)
29
+ Puppet::Pops::PuppetStack.stack('/tmp/test2.pp', 20, self, :raise_error, [exception_class])
30
+ end
31
+
32
+ def two_frames_and_a_raise(exception_class)
33
+ Puppet::Pops::PuppetStack.stack('/tmp/test3.pp', 15, self, :call_raiser, [exception_class])
34
+ end
35
+
36
+ def outer_rescue(exception_class)
37
+ begin
38
+ two_frames_and_a_raise(exception_class)
39
+ rescue Puppet::Error => e
40
+ Puppet.log_exception(e)
41
+ end
42
+ end
43
+
44
+ def run(exception_class)
45
+ Puppet::Pops::PuppetStack.stack('/tmp/test4.pp', 10, self, :outer_rescue, [exception_class])
46
+ end
47
+ end
48
+
16
49
  describe Puppet::Util::Logging do
17
50
  before do
18
51
  @logger = LoggingTester.new
@@ -340,6 +373,173 @@ original
340
373
  .*2\.rb:2:in `b'
341
374
  .*3\.rb:1/)
342
375
  end
376
+
377
+ describe "when trace is disabled" do
378
+ it 'excludes backtrace for RuntimeError in log message' do
379
+ begin
380
+ raise RuntimeError, 'Oops'
381
+ rescue RuntimeError => e
382
+ Puppet.log_exception(e)
383
+ end
384
+
385
+ expect(@logs.size).to eq(1)
386
+ log = @logs[0]
387
+ expect(log.message).to_not match('/logging_spec.rb')
388
+ expect(log.backtrace).to be_nil
389
+ end
390
+
391
+ it "backtrace member is unset when logging ParseErrorWithIssue" do
392
+ begin
393
+ raise Puppet::ParseErrorWithIssue.new('Oops', '/tmp/test.pp', 30, 15, nil, :SYNTAX_ERROR)
394
+ rescue RuntimeError => e
395
+ Puppet.log_exception(e)
396
+ end
397
+
398
+ expect(@logs.size).to eq(1)
399
+ log = @logs[0]
400
+ expect(log.message).to_not match('/logging_spec.rb')
401
+ expect(log.backtrace).to be_nil
402
+ end
403
+ end
404
+
405
+ describe "when trace is enabled" do
406
+ it 'includes backtrace for RuntimeError in log message when enabled globally' do
407
+ Puppet[:trace] = true
408
+ begin
409
+ raise RuntimeError, 'Oops'
410
+ rescue RuntimeError => e
411
+ Puppet.log_exception(e, :default)
412
+ end
413
+ Puppet[:trace] = false
414
+
415
+ expect(@logs.size).to eq(1)
416
+ log = @logs[0]
417
+ expect(log.message).to match('/logging_spec.rb')
418
+ expect(log.backtrace).to be_nil
419
+ end
420
+
421
+ it 'includes backtrace for RuntimeError in log message when enabled via option' do
422
+ begin
423
+ raise RuntimeError, 'Oops'
424
+ rescue RuntimeError => e
425
+ Puppet.log_exception(e, :default, :trace => true)
426
+ end
427
+
428
+ expect(@logs.size).to eq(1)
429
+ log = @logs[0]
430
+ expect(log.message).to match('/logging_spec.rb')
431
+ expect(log.backtrace).to be_nil
432
+ end
433
+
434
+
435
+ it "backtrace member is set when logging ParseErrorWithIssue" do
436
+ begin
437
+ raise Puppet::ParseErrorWithIssue.new('Oops', '/tmp/test.pp', 30, 15, nil, :SYNTAX_ERROR)
438
+ rescue RuntimeError => e
439
+ Puppet.log_exception(e, :default, :trace => true)
440
+ end
441
+
442
+ expect(@logs.size).to eq(1)
443
+ log = @logs[0]
444
+ expect(log.message).to_not match('/logging_spec.rb')
445
+ expect(log.backtrace).to be_a(Array)
446
+ expect(log.backtrace[0]).to match('/logging_spec.rb')
447
+ end
448
+ it "backtrace has interleaved PuppetStack when logging ParseErrorWithIssue" do
449
+ Puppet[:trace] = true
450
+ PuppetStackCreator.new.run(Puppet::ParseErrorWithIssue)
451
+ Puppet[:trace] = false
452
+
453
+ expect(@logs.size).to eq(1)
454
+ log = @logs[0]
455
+ expect(log.message).to_not match('/logging_spec.rb')
456
+ expect(log.backtrace[0]).to match('/logging_spec.rb')
457
+
458
+ expect(log.backtrace[1]).to match('/tmp/test2.pp:20')
459
+ puppetstack = log.backtrace.select { |l| l =~ /tmp\/test\d\.pp/ }
460
+
461
+ expect(puppetstack.length).to equal 3
462
+ end
463
+
464
+ it "message has interleaved PuppetStack when logging ParseError" do
465
+ Puppet[:trace] = true
466
+ PuppetStackCreator.new.run(Puppet::ParseError)
467
+ Puppet[:trace] = false
468
+
469
+ expect(@logs.size).to eq(1)
470
+ log = @logs[0]
471
+
472
+ log_lines = log.message.split("\n")
473
+ expect(log_lines[1]).to match('/logging_spec.rb')
474
+ expect(log_lines[2]).to match('/tmp/test2.pp:20')
475
+ puppetstack = log_lines.select { |l| l =~ /tmp\/test\d\.pp/ }
476
+
477
+ expect(puppetstack.length).to equal 3
478
+ end
479
+ end
480
+
481
+ describe "when trace is disabled but puppet_trace is enabled" do
482
+ it "includes only PuppetStack as backtrace member with ParseErrorWithIssue" do
483
+ Puppet[:trace] = false
484
+ Puppet[:puppet_trace] = true
485
+ PuppetStackCreator.new.run(Puppet::ParseErrorWithIssue)
486
+ Puppet[:trace] = false
487
+ Puppet[:puppet_trace] = false
488
+
489
+ expect(@logs.size).to eq(1)
490
+ log = @logs[0]
491
+
492
+ expect(log.backtrace[0]).to match('/tmp/test2.pp:20')
493
+ expect(log.backtrace.length).to equal 3
494
+ end
495
+
496
+ it "includes only PuppetStack in message with ParseError" do
497
+ Puppet[:trace] = false
498
+ Puppet[:puppet_trace] = true
499
+ PuppetStackCreator.new.run(Puppet::ParseError)
500
+ Puppet[:trace] = false
501
+ Puppet[:puppet_trace] = false
502
+
503
+ expect(@logs.size).to eq(1)
504
+ log = @logs[0]
505
+
506
+ log_lines = log.message.split("\n")
507
+ expect(log_lines[1]).to match('/tmp/test2.pp:20')
508
+ puppetstack = log_lines.select { |l| l =~ /tmp\/test\d\.pp/ }
509
+
510
+ expect(puppetstack.length).to equal 3
511
+ end
512
+ end
513
+
514
+ it 'includes position details for ParseError in log message' do
515
+ begin
516
+ raise Puppet::ParseError.new('Oops', '/tmp/test.pp', 30, 15)
517
+ rescue RuntimeError => e
518
+ Puppet.log_exception(e)
519
+ end
520
+
521
+ expect(@logs.size).to eq(1)
522
+ log = @logs[0]
523
+ expect(log.message).to match(/ \(file: \/tmp\/test\.pp, line: 30, column: 15\)/)
524
+ expect(log.message).to be(log.to_s)
525
+ end
526
+
527
+ it 'excludes position details for ParseErrorWithIssue from log message' do
528
+ begin
529
+ raise Puppet::ParseErrorWithIssue.new('Oops', '/tmp/test.pp', 30, 15, nil, :SYNTAX_ERROR)
530
+ rescue RuntimeError => e
531
+ Puppet.log_exception(e)
532
+ end
533
+
534
+ expect(@logs.size).to eq(1)
535
+ log = @logs[0]
536
+ expect(log.message).to_not match(/ \(file: \/tmp\/test\.pp, line: 30, column: 15\)/)
537
+ expect(log.to_s).to match(/ \(file: \/tmp\/test\.pp, line: 30, column: 15\)/)
538
+ expect(log.issue_code).to eq(:SYNTAX_ERROR)
539
+ expect(log.file).to eq('/tmp/test.pp')
540
+ expect(log.line).to eq(30)
541
+ expect(log.pos).to eq(15)
542
+ end
343
543
  end
344
544
 
345
545
  describe 'when Facter' do