puppet 3.6.0 → 3.6.1

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 (39) hide show
  1. data/ext/rack/example-passenger-vhost.conf +3 -2
  2. data/lib/puppet.rb +10 -0
  3. data/lib/puppet/agent.rb +0 -1
  4. data/lib/puppet/application.rb +16 -18
  5. data/lib/puppet/configurer.rb +16 -21
  6. data/lib/puppet/context.rb +46 -5
  7. data/lib/puppet/indirector/catalog/compiler.rb +4 -3
  8. data/lib/puppet/indirector/rest.rb +5 -6
  9. data/lib/puppet/network/http/route.rb +15 -6
  10. data/lib/puppet/parser/functions/epp.rb +1 -1
  11. data/lib/puppet/pops/evaluator/access_operator.rb +40 -35
  12. data/lib/puppet/pops/parser/egrammar.ra +5 -1
  13. data/lib/puppet/pops/parser/eparser.rb +1096 -1079
  14. data/lib/puppet/pops/parser/interpolation_support.rb +1 -1
  15. data/lib/puppet/pops/parser/lexer2.rb +14 -7
  16. data/lib/puppet/provider/package/rpm.rb +3 -0
  17. data/lib/puppet/provider/package/yum.rb +15 -7
  18. data/lib/puppet/provider/package/zypper.rb +3 -2
  19. data/lib/puppet/ssl/host.rb +1 -1
  20. data/lib/puppet/test/test_helper.rb +34 -1
  21. data/lib/puppet/type/package.rb +12 -1
  22. data/lib/puppet/version.rb +1 -1
  23. data/spec/unit/configurer_spec.rb +36 -7
  24. data/spec/unit/context_spec.rb +39 -0
  25. data/spec/unit/indirector/catalog/compiler_spec.rb +16 -0
  26. data/spec/unit/indirector/rest_spec.rb +17 -3
  27. data/spec/unit/network/http/route_spec.rb +16 -0
  28. data/spec/unit/parser/functions/epp_spec.rb +15 -0
  29. data/spec/unit/pops/evaluator/access_ops_spec.rb +6 -0
  30. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +10 -0
  31. data/spec/unit/pops/parser/lexer2_spec.rb +10 -2
  32. data/spec/unit/provider/package/aptrpm_spec.rb +0 -1
  33. data/spec/unit/provider/package/rpm_spec.rb +8 -2
  34. data/spec/unit/provider/package/yum_spec.rb +40 -23
  35. data/spec/unit/provider/package/zypper_spec.rb +25 -6
  36. data/spec/unit/ssl/host_spec.rb +5 -5
  37. data/spec/unit/type/package_spec.rb +21 -1
  38. metadata +3157 -3147
  39. checksums.yaml +0 -7
@@ -208,7 +208,7 @@ module Puppet::Pops::Parser::InterpolationSupport
208
208
 
209
209
  def transform_to_variable(token)
210
210
  token_name = token[0]
211
- if [:NUMBER, :NAME].include?(token_name) || self.class::KEYWORD_NAMES[token_name]
211
+ if [:NUMBER, :NAME, :WORD].include?(token_name) || self.class::KEYWORD_NAMES[token_name]
212
212
  t = token[1]
213
213
  ta = t.token_array
214
214
  [:VARIABLE, self.class::TokenValue.new([:VARIABLE, ta[1], ta[2]], t.offset, t.locator)]
@@ -87,6 +87,7 @@ class Puppet::Pops::Parser::Lexer2
87
87
 
88
88
  # Tokens that are always unique to what has been lexed
89
89
  TOKEN_STRING = [:STRING, nil, 0].freeze
90
+ TOKEN_WORD = [:WORD, nil, 0].freeze
90
91
  TOKEN_DQPRE = [:DQPRE, nil, 0].freeze
91
92
  TOKEN_DQMID = [:DQPRE, nil, 0].freeze
92
93
  TOKEN_DQPOS = [:DQPRE, nil, 0].freeze
@@ -157,6 +158,7 @@ class Puppet::Pops::Parser::Lexer2
157
158
  #
158
159
  PATTERN_CLASSREF = %r{((::){0,1}[A-Z][\w]*)+}
159
160
  PATTERN_NAME = %r{((::)?[a-z][\w]*)(::[a-z][\w]*)*}
161
+
160
162
  PATTERN_BARE_WORD = %r{[a-z_](?:[\w-]*[\w])?}
161
163
 
162
164
  PATTERN_DOLLAR_VAR = %r{\$(::)?(\w+::)*\w+}
@@ -573,21 +575,26 @@ class Puppet::Pops::Parser::Lexer2
573
575
  end
574
576
 
575
577
  when 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
576
- 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
578
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '_'
577
579
  value = scn.scan(PATTERN_NAME)
578
- # NAME or false start because followed by hyphen(s) and word
579
- if value && !scn.match?(/-+\w/)
580
+ # NAME or false start because followed by hyphen(s), underscore or word
581
+ if value && !scn.match?(/^-+\w/)
580
582
  emit_completed(KEYWORDS[value] || [:NAME, value, scn.pos - before], before)
581
583
  else
582
584
  # Restart and check entire pattern (for ease of detecting non allowed trailing hyphen)
583
585
  scn.pos = before
584
586
  value = scn.scan(PATTERN_BARE_WORD)
585
- if value
586
- emit_completed([:STRING, value, scn.pos - before], before)
587
+ # If the WORD continues with :: it must be a correct fully qualified name
588
+ if value && !(fully_qualified = scn.match?(/::/))
589
+ emit_completed([:WORD, value, scn.pos - before], before)
587
590
  else
588
- # move to faulty position ([a-z] was ok)
591
+ # move to faulty position ([a-z_] was ok)
589
592
  scn.pos = scn.pos + 1
590
- lex_error("Illegal name")
593
+ if fully_qualified
594
+ lex_error("Illegal fully qualified name")
595
+ else
596
+ lex_error("Illegal name or bare word")
597
+ end
591
598
  end
592
599
  end
593
600
 
@@ -15,6 +15,7 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr
15
15
  has_feature :versionable
16
16
  has_feature :install_options
17
17
  has_feature :uninstall_options
18
+ has_feature :virtual_packages
18
19
 
19
20
  # Note: self:: is required here to keep these constants in the context of what will
20
21
  # eventually become this Puppet::Type::Package::ProviderRpm class.
@@ -82,6 +83,8 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr
82
83
  begin
83
84
  output = rpm(*cmd)
84
85
  rescue Puppet::ExecutionFailure
86
+ return nil unless @resource.allow_virtual?
87
+
85
88
  # rpm -q exits 1 if package not found
86
89
  # retry the query for virtual packages
87
90
  cmd << '--whatprovides'
@@ -7,7 +7,7 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
7
7
  remove dependent packages with this provider use the `purgeable` feature, but note this
8
8
  feature is destructive and should be used with the utmost care."
9
9
 
10
- has_feature :install_options, :versionable
10
+ has_feature :install_options, :versionable, :virtual_packages
11
11
 
12
12
  commands :yum => "yum", :rpm => "rpm", :python => "python"
13
13
 
@@ -90,9 +90,14 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
90
90
  end
91
91
 
92
92
  def install
93
+ wanted = @resource[:name]
94
+ # If not allowing virtual packages, do a query to ensure a real package exists
95
+ unless @resource.allow_virtual?
96
+ yum '-d', '0', '-e', '0', '-y', :list, wanted
97
+ end
98
+
93
99
  should = @resource.should(:ensure)
94
100
  self.debug "Ensuring => #{should}"
95
- wanted = @resource[:name]
96
101
  operation = :install
97
102
 
98
103
  case should
@@ -113,12 +118,15 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
113
118
  yum *args
114
119
 
115
120
 
116
- is = self.query
117
- raise Puppet::Error, "Could not find package #{self.name}" unless is
121
+ # If a version was specified, query again to see if it is a matching version
122
+ if should
123
+ is = self.query
124
+ raise Puppet::Error, "Could not find package #{self.name}" unless is
118
125
 
119
- # FIXME: Should we raise an exception even if should == :latest
120
- # and yum updated us to a version other than @param_hash[:ensure] ?
121
- raise Puppet::Error, "Failed to update to version #{should}, got version #{is[:ensure]} instead" if should && should != is[:ensure]
126
+ # FIXME: Should we raise an exception even if should == :latest
127
+ # and yum updated us to a version other than @param_hash[:ensure] ?
128
+ raise Puppet::Error, "Failed to update to version #{should}, got version #{is[:ensure]} instead" if should != is[:ensure]
129
+ end
122
130
  end
123
131
 
124
132
  # What's the latest package version available?
@@ -1,7 +1,7 @@
1
1
  Puppet::Type.type(:package).provide :zypper, :parent => :rpm do
2
2
  desc "Support for SuSE `zypper` package manager. Found in SLES10sp2+ and SLES11"
3
3
 
4
- has_feature :versionable, :install_options
4
+ has_feature :versionable, :install_options, :virtual_packages
5
5
 
6
6
  commands :zypper => "/usr/bin/zypper"
7
7
 
@@ -23,7 +23,7 @@ Puppet::Type.type(:package).provide :zypper, :parent => :rpm do
23
23
  # XXX: We don't actually deal with epochs here.
24
24
  case should
25
25
  when true, false, Symbol
26
- # pass
26
+ should = nil
27
27
  else
28
28
  # Add the package version
29
29
  wanted = "#{wanted}-#{should}"
@@ -52,6 +52,7 @@ Puppet::Type.type(:package).provide :zypper, :parent => :rpm do
52
52
  #zypper 0.6.13 (OpenSuSE 10.2) does not support auto agree with licenses
53
53
  options << '--auto-agree-with-licenses' unless major < 1 and minor <= 6 and patch <= 13
54
54
  options << '--no-confirm'
55
+ options << '--name' unless @resource.allow_virtual? || should
55
56
  options += install_options if resource[:install_options]
56
57
  options << wanted
57
58
 
@@ -203,7 +203,7 @@ DOC
203
203
 
204
204
  # get the CA cert first, since it's required for the normal cert
205
205
  # to be of any use.
206
- return nil unless Certificate.indirection.find("ca") unless ca?
206
+ return nil unless Certificate.indirection.find("ca", :fail_on_404 => true) unless ca?
207
207
  return nil unless @certificate = Certificate.indirection.find(name)
208
208
 
209
209
  validate_certificate_with_key
@@ -36,6 +36,19 @@ module Puppet::Test
36
36
  # that call Puppet.
37
37
  # @return nil
38
38
  def self.initialize()
39
+ # This meta class instance variable is used as a guard to ensure that
40
+ # before_each, and after_each are only called once. This problem occurs
41
+ # when there are more than one puppet test infrastructure "orchestrator in us.
42
+ # The use of both puppetabs-spec_helper, and rodjek-rspec_puppet will cause
43
+ # two resets of the puppet environment, and will cause problem rolling back to
44
+ # a known point as there is no way to differentiate where the calls are coming
45
+ # from. See more information in #before_each_test, and #after_each_test
46
+ # Note that the variable is only initialized to 0 if nil. This is important
47
+ # as more than one orchestrator will call initialize. A second call can not
48
+ # simply set it to 0 since that would potentially destroy an active guard.
49
+ #
50
+ @@reentry_count ||= 0
51
+
39
52
  owner = Process.pid
40
53
  Puppet.push_context(Puppet.base_context({
41
54
  :environmentpath => "",
@@ -58,9 +71,24 @@ module Puppet::Test
58
71
  def self.after_all_tests()
59
72
  end
60
73
 
74
+ # The name of the rollback mark used in the Puppet.context. This is what
75
+ # the test infrastructure returns to for each test.
76
+ #
77
+ ROLLBACK_MARK = "initial testing state"
78
+
61
79
  # Call this method once per test, prior to execution of each invididual test.
62
80
  # @return nil
63
81
  def self.before_each_test()
82
+ # When using both rspec-puppet and puppet-rspec-helper, there are two packages trying
83
+ # to be helpful and orchestrate the callback sequence. We let only the first win, the
84
+ # second callback results in a no-op.
85
+ # Likewise when entering after_each_test(), a check is made to make tear down happen
86
+ # only once.
87
+ #
88
+ return unless @@reentry_count == 0
89
+ @@reentry_count = 1
90
+
91
+ Puppet.mark_context(ROLLBACK_MARK)
64
92
 
65
93
  # We need to preserve the current state of all our indirection cache and
66
94
  # terminus classes. This is pretty important, because changes to these
@@ -112,6 +140,11 @@ module Puppet::Test
112
140
  # Call this method once per test, after execution of each individual test.
113
141
  # @return nil
114
142
  def self.after_each_test()
143
+ # Ensure that a matching tear down only happens once per completed setup
144
+ # (see #before_each_test).
145
+ return unless @@reentry_count == 1
146
+ @@reentry_count = 0
147
+
115
148
  Puppet.settings.send(:clear_everything_for_tests)
116
149
 
117
150
  Puppet::Util::Storage.clear
@@ -153,7 +186,7 @@ module Puppet::Test
153
186
  $LOAD_PATH.clear
154
187
  $old_load_path.each {|x| $LOAD_PATH << x }
155
188
 
156
- Puppet.pop_context
189
+ Puppet.rollback_context(ROLLBACK_MARK)
157
190
  end
158
191
 
159
192
 
@@ -4,6 +4,7 @@
4
4
  # systems.
5
5
 
6
6
  require 'puppet/parameter/package_options'
7
+ require 'puppet/parameter/boolean'
7
8
 
8
9
  module Puppet
9
10
  newtype(:package) do
@@ -54,7 +55,7 @@ module Puppet
54
55
  ensured for the given package. The meaning and format of these settings is
55
56
  provider-specific.",
56
57
  :methods => [:package_settings_insync?, :package_settings, :package_settings=]
57
-
58
+ feature :virtual_packages, "The provider accepts virtual package names for install and uninstall."
58
59
 
59
60
  ensurable do
60
61
  desc <<-EOT
@@ -421,6 +422,16 @@ module Puppet
421
422
  EOT
422
423
  end
423
424
 
425
+ newparam(:allow_virtual, :boolean => true, :parent => Puppet::Parameter::Boolean, :required_features => :virtual_packages) do
426
+ desc 'Specifies if virtual package names are allowed for install and uninstall.'
427
+
428
+ # In a future release, this should be defaulted to true and the below deprecation warning removed
429
+ defaultto do
430
+ Puppet.deprecation_warning('The package type\'s allow_virtual parameter will be changing its default value from false to true in a future release. If you do not want to allow virtual packages, please explicitly set allow_virtual to false.') unless value
431
+ false
432
+ end
433
+ end
434
+
424
435
  autorequire(:file) do
425
436
  autos = []
426
437
  [:responsefile, :adminfile].each { |param|
@@ -7,7 +7,7 @@
7
7
 
8
8
 
9
9
  module Puppet
10
- PUPPETVERSION = '3.6.0'
10
+ PUPPETVERSION = '3.6.1'
11
11
 
12
12
  ##
13
13
  # version is a public API method intended to always provide a fast and
@@ -204,19 +204,25 @@ describe Puppet::Configurer do
204
204
  end
205
205
 
206
206
  it "should send the report" do
207
- report = Puppet::Transaction::Report.new("apply")
207
+ report = Puppet::Transaction::Report.new("apply", nil, "test", "aaaa")
208
208
  Puppet::Transaction::Report.expects(:new).returns(report)
209
209
  @agent.expects(:send_report).with(report)
210
210
 
211
+ report.environment.should == "test"
212
+ report.transaction_uuid.should == "aaaa"
213
+
211
214
  @agent.run
212
215
  end
213
216
 
214
217
  it "should send the transaction report even if the catalog could not be retrieved" do
215
218
  @agent.expects(:retrieve_catalog).returns nil
216
219
 
217
- report = Puppet::Transaction::Report.new("apply")
220
+ report = Puppet::Transaction::Report.new("apply", nil, "test", "aaaa")
218
221
  Puppet::Transaction::Report.expects(:new).returns(report)
219
- @agent.expects(:send_report)
222
+ @agent.expects(:send_report).with(report)
223
+
224
+ report.environment.should == "test"
225
+ report.transaction_uuid.should == "aaaa"
220
226
 
221
227
  @agent.run
222
228
  end
@@ -224,9 +230,12 @@ describe Puppet::Configurer do
224
230
  it "should send the transaction report even if there is a failure" do
225
231
  @agent.expects(:retrieve_catalog).raises "whatever"
226
232
 
227
- report = Puppet::Transaction::Report.new("apply")
233
+ report = Puppet::Transaction::Report.new("apply", nil, "test", "aaaa")
228
234
  Puppet::Transaction::Report.expects(:new).returns(report)
229
- @agent.expects(:send_report)
235
+ @agent.expects(:send_report).with(report)
236
+
237
+ report.environment.should == "test"
238
+ report.transaction_uuid.should == "aaaa"
230
239
 
231
240
  @agent.run.should be_nil
232
241
  end
@@ -254,7 +263,7 @@ describe Puppet::Configurer do
254
263
 
255
264
  Puppet.settings[:prerun_command] = "/my/command"
256
265
  Puppet::Util::Execution.expects(:execute).with(["/my/command"]).raises(Puppet::ExecutionFailure, "Failed")
257
- @agent.expects(:send_report)
266
+ @agent.expects(:send_report).with(report)
258
267
 
259
268
  @agent.run.should be_nil
260
269
  end
@@ -276,7 +285,7 @@ describe Puppet::Configurer do
276
285
 
277
286
  Puppet.settings[:postrun_command] = "/my/command"
278
287
  Puppet::Util::Execution.expects(:execute).with(["/my/command"]).raises(Puppet::ExecutionFailure, "Failed")
279
- @agent.expects(:send_report)
288
+ @agent.expects(:send_report).with(report)
280
289
 
281
290
  @agent.run.should be_nil
282
291
  end
@@ -351,6 +360,19 @@ describe Puppet::Configurer do
351
360
  @agent.environment.should == "second_env"
352
361
  end
353
362
 
363
+ it "should fix the report if the server specifies a new environment in the catalog" do
364
+ report = Puppet::Transaction::Report.new("apply", nil, "test", "aaaa")
365
+ Puppet::Transaction::Report.expects(:new).returns(report)
366
+ @agent.expects(:send_report).with(report)
367
+
368
+ @catalog.stubs(:environment).returns("second_env")
369
+ @agent.stubs(:retrieve_catalog).returns(@catalog)
370
+
371
+ @agent.run
372
+
373
+ report.environment.should == "second_env"
374
+ end
375
+
354
376
  it "should clear the global caches" do
355
377
  $env_module_directories = false
356
378
 
@@ -508,6 +530,13 @@ describe Puppet::Configurer do
508
530
  end
509
531
  end
510
532
 
533
+ describe "when requesting a node" do
534
+ it "uses the transaction uuid in the request" do
535
+ Puppet::Node.indirection.expects(:find).with(anything, has_entries(:transaction_uuid => anything)).twice
536
+ @agent.run
537
+ end
538
+ end
539
+
511
540
  describe "when retrieving a catalog" do
512
541
  before do
513
542
  Puppet.settings.stubs(:use).returns(true)
@@ -72,6 +72,45 @@ describe Puppet::Context do
72
72
  end
73
73
  end
74
74
 
75
+ context "a rollback" do
76
+ it "returns to the mark" do
77
+ context.push("a" => 1)
78
+ context.mark("start")
79
+ context.push("a" => 2)
80
+ context.push("a" => 3)
81
+ context.pop
82
+
83
+ context.rollback("start")
84
+
85
+ expect(context.lookup("a")).to eq(1)
86
+ end
87
+
88
+ it "rolls back to the mark across a scoped override" do
89
+ context.push("a" => 1)
90
+ context.mark("start")
91
+ context.override("a" => 3) do
92
+
93
+ context.rollback("start")
94
+
95
+ expect(context.lookup("a")).to eq(1)
96
+ end
97
+ expect(context.lookup("a")).to eq(1)
98
+ end
99
+
100
+ it "fails to rollback to an unknown mark" do
101
+ expect do
102
+ context.rollback("unknown")
103
+ end.to raise_error(Puppet::Context::UnknownRollbackMarkError)
104
+ end
105
+
106
+ it "does not allow the same mark to be set twice" do
107
+ context.mark("duplicate")
108
+ expect do
109
+ context.mark("duplicate")
110
+ end.to raise_error(Puppet::Context::DuplicateRollbackMarkError)
111
+ end
112
+ end
113
+
75
114
  context 'support lazy entries' do
76
115
  it 'by evaluating a bound proc' do
77
116
  result = nil
@@ -191,6 +191,22 @@ describe Puppet::Resource::Catalog::Compiler do
191
191
 
192
192
  compiler.find(request)
193
193
  end
194
+
195
+ it "should pass the transaction_uuid to the node indirection" do
196
+ uuid = '793ff10d-89f8-4527-a645-3302cbc749f3'
197
+ node = Puppet::Node.new("thing")
198
+ compiler = Puppet::Resource::Catalog::Compiler.new
199
+ compiler.stubs(:compile)
200
+ request = Puppet::Indirector::Request.new(:catalog, :find, "thing",
201
+ nil, :transaction_uuid => uuid)
202
+
203
+ Puppet::Node.indirection.expects(:find).with(
204
+ "thing",
205
+ has_entries(:transaction_uuid => uuid)
206
+ ).returns(node)
207
+
208
+ compiler.find(request)
209
+ end
194
210
  end
195
211
 
196
212
  describe "after finding nodes" do
@@ -277,12 +277,26 @@ describe Puppet::Indirector::REST do
277
277
  terminus.find(request).should == nil
278
278
  end
279
279
 
280
- it 'raises a warning for a 404' do
280
+ it 'raises no warning for a 404 (when not asked to do so)' do
281
281
  response = mock_response('404', 'this is the notfound you are looking for')
282
282
  connection.expects(:get).returns(response)
283
283
  expected_message = 'Find /production/test_model/foo? resulted in 404 with the message: this is the notfound you are looking for'
284
- Puppet::Util::Warnings.expects(:maybe_log).with(expected_message, Puppet::TestModel::Rest)
285
- terminus.find(request)
284
+ expect{terminus.find(request)}.to_not raise_error()
285
+ end
286
+
287
+ context 'when fail_on_404 is used in request' do
288
+ let(:request) { find_request('foo', :fail_on_404 => true) }
289
+
290
+ it 'raises an error for a 404 when asked to do so' do
291
+ response = mock_response('404', 'this is the notfound you are looking for')
292
+ connection.expects(:get).returns(response)
293
+ expected_message = [
294
+ 'Find /production/test_model/foo?fail_on_404=true',
295
+ 'resulted in 404 with the message: this is the notfound you are looking for'].join( ' ')
296
+ expect do
297
+ terminus.find(request)
298
+ end.to raise_error(Puppet::Error, expected_message)
299
+ end
286
300
  end
287
301
 
288
302
  it "asks the model to deserialize the response body and sets the name on the resulting object to the find key" do