puppet 2.7.20 → 2.7.21

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 (81) hide show
  1. data/CHANGELOG +226 -0
  2. data/conf/auth.conf +3 -3
  3. data/ext/packaging/README.md +191 -57
  4. data/ext/packaging/spec/spec_helper.rb +2 -2
  5. data/ext/packaging/spec/tasks/00_utils_spec.rb +63 -18
  6. data/ext/packaging/spec/tasks/build_object_spec.rb +171 -0
  7. data/ext/packaging/tasks/00_utils.rake +186 -33
  8. data/ext/packaging/tasks/10_setupvars.rake +94 -65
  9. data/ext/packaging/tasks/20_setupextravars.rake +45 -26
  10. data/ext/packaging/tasks/30_metrics.rake +41 -0
  11. data/ext/packaging/tasks/apple.rake +92 -36
  12. data/ext/packaging/tasks/build.rake +183 -0
  13. data/ext/packaging/tasks/deb.rake +45 -40
  14. data/ext/packaging/tasks/deb_repos.rake +103 -0
  15. data/ext/packaging/tasks/doc.rake +5 -5
  16. data/ext/packaging/tasks/fetch.rake +35 -10
  17. data/ext/packaging/tasks/gem.rake +38 -27
  18. data/ext/packaging/tasks/ips.rake +14 -14
  19. data/ext/packaging/tasks/jenkins.rake +337 -0
  20. data/ext/packaging/tasks/mock.rake +153 -72
  21. data/ext/packaging/tasks/pe_deb.rake +2 -2
  22. data/ext/packaging/tasks/pe_remote.rake +22 -19
  23. data/ext/packaging/tasks/pe_rpm.rake +5 -5
  24. data/ext/packaging/tasks/pe_ship.rake +31 -21
  25. data/ext/packaging/tasks/pe_sign.rake +20 -19
  26. data/ext/packaging/tasks/pe_sles.rake +40 -36
  27. data/ext/packaging/tasks/pe_tar.rake +5 -0
  28. data/ext/packaging/tasks/release.rake +32 -12
  29. data/ext/packaging/tasks/remote_build.rake +141 -83
  30. data/ext/packaging/tasks/retrieve.rake +23 -0
  31. data/ext/packaging/tasks/rpm.rake +11 -19
  32. data/ext/packaging/tasks/rpm_repos.rake +127 -0
  33. data/ext/packaging/tasks/ship.rake +68 -55
  34. data/ext/packaging/tasks/sign.rake +38 -10
  35. data/ext/packaging/tasks/tar.rake +25 -9
  36. data/ext/packaging/tasks/update.rake +2 -2
  37. data/ext/packaging/tasks/version.rake +34 -14
  38. data/ext/packaging/tasks/z_data_dump.rake +33 -0
  39. data/lib/puppet/indirector/catalog/compiler.rb +13 -2
  40. data/lib/puppet/indirector/certificate_status/file.rb +5 -0
  41. data/lib/puppet/indirector/errors.rb +5 -0
  42. data/lib/puppet/indirector/file_bucket_file/file.rb +4 -0
  43. data/lib/puppet/indirector/file_bucket_file/selector.rb +4 -0
  44. data/lib/puppet/indirector/indirection.rb +1 -0
  45. data/lib/puppet/indirector/resource/active_record.rb +3 -0
  46. data/lib/puppet/indirector/resource/ral.rb +4 -0
  47. data/lib/puppet/indirector/resource/store_configs.rb +3 -0
  48. data/lib/puppet/indirector/resource/validator.rb +8 -0
  49. data/lib/puppet/indirector/rest.rb +8 -0
  50. data/lib/puppet/indirector/run/local.rb +4 -0
  51. data/lib/puppet/indirector/terminus.rb +20 -0
  52. data/lib/puppet/network/formats.rb +3 -3
  53. data/lib/puppet/network/handler/master.rb +1 -1
  54. data/lib/puppet/network/handler/report.rb +1 -1
  55. data/lib/puppet/network/http/handler.rb +7 -1
  56. data/lib/puppet/network/http/rack/rest.rb +7 -2
  57. data/lib/puppet/network/http/webrick.rb +1 -0
  58. data/lib/puppet/network/rest_authconfig.rb +1 -1
  59. data/lib/puppet/parser/templatewrapper.rb +17 -17
  60. data/lib/puppet/util/monkey_patches.rb +58 -0
  61. data/lib/puppet/version.rb +1 -1
  62. data/spec/integration/indirector/catalog/compiler_spec.rb +1 -0
  63. data/spec/integration/indirector/catalog/queue_spec.rb +1 -1
  64. data/spec/integration/resource/catalog_spec.rb +1 -0
  65. data/spec/unit/indirector/catalog/compiler_spec.rb +29 -2
  66. data/spec/unit/indirector/indirection_spec.rb +18 -1
  67. data/spec/unit/indirector/terminus_spec.rb +191 -177
  68. data/spec/unit/network/formats_spec.rb +6 -6
  69. data/spec/unit/network/http/handler_spec.rb +25 -0
  70. data/spec/unit/network/http/rack/rest_spec.rb +17 -0
  71. data/spec/unit/network/http/webrick_spec.rb +4 -0
  72. data/spec/unit/network/http_pool_spec.rb +0 -1
  73. data/spec/unit/network/rest_authconfig_spec.rb +16 -1
  74. data/spec/unit/parser/functions/inline_template_spec.rb +13 -0
  75. data/spec/unit/parser/functions/template_spec.rb +15 -0
  76. data/spec/unit/parser/templatewrapper_spec.rb +19 -4
  77. data/spec/unit/ssl/certificate_request_spec.rb +2 -0
  78. data/spec/unit/ssl/host_spec.rb +1 -0
  79. data/spec/unit/util/monkey_patches_spec.rb +12 -0
  80. data/test/language/snippets.rb +1 -1
  81. metadata +13 -2
@@ -106,6 +106,7 @@ class Puppet::Network::HTTP::WEBrick
106
106
  results[:SSLCertificate] = host.certificate.content
107
107
  results[:SSLStartImmediately] = true
108
108
  results[:SSLEnable] = true
109
+ results[:SSLOptions] = OpenSSL::SSL::OP_NO_SSLv2
109
110
 
110
111
  raise Puppet::Error, "Could not find CA certificate" unless Puppet::SSL::Certificate.indirection.find(Puppet::SSL::CA_NAME)
111
112
 
@@ -13,7 +13,7 @@ module Puppet
13
13
  # to fileserver.conf
14
14
  { :acl => "/file" },
15
15
  { :acl => "/certificate_revocation_list/ca", :method => :find, :authenticated => true },
16
- { :acl => "/report", :method => :save, :authenticated => true },
16
+ { :acl => "~ ^\/report\/([^\/]+)$", :method => :save, :allow => '$1', :authenticated => true },
17
17
  # These allow `auth any`, because if you can do them anonymously you
18
18
  # should probably also be able to do them when trusted.
19
19
  { :acl => "/certificate/ca", :method => :find, :authenticated => :any },
@@ -5,8 +5,6 @@ require 'erb'
5
5
 
6
6
  class Puppet::Parser::TemplateWrapper
7
7
  attr_writer :scope
8
- attr_reader :file
9
- attr_accessor :string
10
8
  include Puppet::Util
11
9
  Puppet::Util.logmethods(self)
12
10
 
@@ -14,18 +12,22 @@ class Puppet::Parser::TemplateWrapper
14
12
  @__scope__ = scope
15
13
  end
16
14
 
15
+ def file
16
+ @__file__
17
+ end
18
+
17
19
  def scope
18
20
  @__scope__
19
21
  end
20
22
 
21
23
  def script_line
22
24
  # find which line in the template (if any) we were called from
23
- (caller.find { |l| l =~ /#{file}:/ }||"")[/:(\d+):/,1]
25
+ (caller.find { |l| l =~ /#{@__file__}:/ }||"")[/:(\d+):/,1]
24
26
  end
25
27
 
26
28
  # Should return true if a variable is defined, false if it is not
27
29
  def has_variable?(name)
28
- scope.lookupvar(name.to_s, :file => file, :line => script_line) != :undefined
30
+ scope.lookupvar(name.to_s, :file => @__file__, :line => script_line) != :undefined
29
31
  end
30
32
 
31
33
  # Allow templates to access the defined classes
@@ -56,53 +58,51 @@ class Puppet::Parser::TemplateWrapper
56
58
  # the missing_method definition here until we declare the syntax finally
57
59
  # dead.
58
60
  def method_missing(name, *args)
59
- value = scope.lookupvar(name.to_s,:file => file,:line => script_line)
61
+ value = scope.lookupvar(name.to_s,:file => @__file__,:line => script_line)
60
62
  if value != :undefined
61
63
  return value
62
64
  else
63
65
  # Just throw an error immediately, instead of searching for
64
66
  # other missingmethod things or whatever.
65
- raise Puppet::ParseError.new("Could not find value for '#{name}'",@file,script_line)
67
+ raise Puppet::ParseError.new("Could not find value for '#{name}'", @__file__, script_line)
66
68
  end
67
69
  end
68
70
 
69
71
  def file=(filename)
70
- unless @file = Puppet::Parser::Files.find_template(filename, scope.compiler.environment.to_s)
72
+ unless @__file__ = Puppet::Parser::Files.find_template(filename, scope.compiler.environment.to_s)
71
73
  raise Puppet::ParseError, "Could not find template '#{filename}'"
72
74
  end
73
75
 
74
76
  # We'll only ever not have a parser in testing, but, eh.
75
- scope.known_resource_types.watch_file(file)
76
-
77
- @string = File.read(file)
77
+ scope.known_resource_types.watch_file(@__file__)
78
78
  end
79
79
 
80
80
  def result(string = nil)
81
81
  if string
82
- self.string = string
83
82
  template_source = "inline template"
84
83
  else
85
- template_source = file
84
+ string = File.read(@__file__)
85
+ template_source = @__file__
86
86
  end
87
87
 
88
88
  # Expose all the variables in our scope as instance variables of the
89
89
  # current object, making it possible to access them without conflict
90
90
  # to the regular methods.
91
91
  benchmark(:debug, "Bound template variables for #{template_source}") do
92
- scope.to_hash.each { |name, value|
92
+ scope.to_hash.each do |name, value|
93
93
  if name.kind_of?(String)
94
94
  realname = name.gsub(/[^\w]/, "_")
95
95
  else
96
96
  realname = name
97
97
  end
98
98
  instance_variable_set("@#{realname}", value)
99
- }
99
+ end
100
100
  end
101
101
 
102
102
  result = nil
103
103
  benchmark(:debug, "Interpolated template #{template_source}") do
104
- template = ERB.new(self.string, 0, "-")
105
- template.filename = file
104
+ template = ERB.new(string, 0, "-")
105
+ template.filename = @__file__
106
106
  result = template.result(binding)
107
107
  end
108
108
 
@@ -110,6 +110,6 @@ class Puppet::Parser::TemplateWrapper
110
110
  end
111
111
 
112
112
  def to_s
113
- "template[#{(file ? file : "inline")}]"
113
+ "template[#{(@__file__ ? @__file__ : "inline")}]"
114
114
  end
115
115
  end
@@ -34,6 +34,21 @@ end
34
34
  end
35
35
  }
36
36
 
37
+ if defined?(YAML::ENGINE) and YAML::ENGINE.yamler == 'psych'
38
+ def Psych.safely_load(str)
39
+ result = Psych.parse(str)
40
+ if invalid_node = result.find { |node| node.tag =~ /!map:(.*)/ || node.tag =~ /!ruby\/hash:(.*)/ }
41
+ raise ArgumentError, "Illegal YAML mapping found with tag #{invalid_node.tag}; please use !ruby/object:#{$1} instead"
42
+ else
43
+ result.to_ruby
44
+ end
45
+ end
46
+ else
47
+ def YAML.safely_load(str)
48
+ self.load(str)
49
+ end
50
+ end
51
+
37
52
  def YAML.dump(*args)
38
53
  ZAML.dump(*args)
39
54
  end
@@ -241,3 +256,46 @@ if RUBY_VERSION == '1.8.5'
241
256
  module_function :move
242
257
  end
243
258
  end
259
+
260
+ # (#19151) Reject all SSLv2 ciphers and handshakes
261
+ require 'openssl'
262
+ class OpenSSL::SSL::SSLContext
263
+ if match = /^1\.8\.(\d+)/.match(RUBY_VERSION)
264
+ older_than_187 = match[1].to_i < 7
265
+ else
266
+ older_than_187 = false
267
+ end
268
+
269
+ alias __original_initialize initialize
270
+ private :__original_initialize
271
+
272
+ if older_than_187
273
+ def initialize(*args)
274
+ __original_initialize(*args)
275
+ if bitmask = self.options
276
+ self.options = bitmask | OpenSSL::SSL::OP_NO_SSLv2
277
+ else
278
+ self.options = OpenSSL::SSL::OP_NO_SSLv2
279
+ end
280
+ # These are the default ciphers in recent MRI versions. See
281
+ # https://github.com/ruby/ruby/blob/v1_9_3_392/ext/openssl/lib/openssl/ssl-internal.rb#L26
282
+ self.ciphers = "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW"
283
+ end
284
+ else
285
+ if DEFAULT_PARAMS[:options]
286
+ DEFAULT_PARAMS[:options] |= OpenSSL::SSL::OP_NO_SSLv2
287
+ else
288
+ DEFAULT_PARAMS[:options] = OpenSSL::SSL::OP_NO_SSLv2
289
+ end
290
+ DEFAULT_PARAMS[:ciphers] << ':!SSLv2'
291
+
292
+ def initialize(*args)
293
+ __original_initialize(*args)
294
+ params = {
295
+ :options => DEFAULT_PARAMS[:options],
296
+ :ciphers => DEFAULT_PARAMS[:ciphers],
297
+ }
298
+ set_params(params)
299
+ end
300
+ end
301
+ end
@@ -6,7 +6,7 @@
6
6
  # Raketasks and such to set the version based on the output of `git describe`
7
7
  #
8
8
  module Puppet
9
- PUPPETVERSION = '2.7.20'
9
+ PUPPETVERSION = '2.7.21'
10
10
 
11
11
  def self.version
12
12
  @puppet_version || PUPPETVERSION
@@ -11,6 +11,7 @@ describe Puppet::Resource::Catalog::Compiler do
11
11
  @catalog = Puppet::Resource::Catalog.new
12
12
  @catalog.add_resource(@one = Puppet::Resource.new(:file, "/one"))
13
13
  @catalog.add_resource(@two = Puppet::Resource.new(:file, "/two"))
14
+ Puppet::Resource::Catalog.indirection.terminus.stubs(:validate)
14
15
  end
15
16
 
16
17
  after { Puppet.settings.clear }
@@ -6,7 +6,7 @@ require 'puppet/resource/catalog'
6
6
  describe "Puppet::Resource::Catalog::Queue", :if => Puppet.features.pson? do
7
7
  before do
8
8
  Puppet::Resource::Catalog.indirection.terminus(:queue)
9
- @catalog = Puppet::Resource::Catalog.new
9
+ @catalog = Puppet::Resource::Catalog.new("foo")
10
10
 
11
11
  @one = Puppet::Resource.new(:file, "/one")
12
12
  @two = Puppet::Resource.new(:file, "/two")
@@ -48,6 +48,7 @@ describe Puppet::Resource::Catalog do
48
48
  Puppet::Resource::Catalog.indirection.stubs(:terminus).returns terminus
49
49
 
50
50
  node = mock 'node'
51
+ terminus.stubs(:validate)
51
52
  terminus.expects(:find).with { |request| request.options[:use_node] == node }
52
53
  Puppet::Resource::Catalog.indirection.find("me", :use_node => node)
53
54
  end
@@ -53,13 +53,22 @@ describe Puppet::Resource::Catalog::Compiler do
53
53
  @request = stub 'request', :key => @name, :node => @name, :options => {}
54
54
  end
55
55
 
56
- it "should directly use provided nodes" do
56
+ it "should directly use provided nodes for a local request" do
57
57
  Puppet::Node.indirection.expects(:find).never
58
58
  @compiler.expects(:compile).with(@node)
59
59
  @request.stubs(:options).returns(:use_node => @node)
60
+ @request.stubs(:remote?).returns(false)
60
61
  @compiler.find(@request)
61
62
  end
62
63
 
64
+ it "rejects a provided node if the request is remote" do
65
+ @request.stubs(:options).returns(:use_node => @node)
66
+ @request.stubs(:remote?).returns(true)
67
+ expect {
68
+ @compiler.find(@request)
69
+ }.to raise_error Puppet::Error, /invalid option use_node/i
70
+ end
71
+
63
72
  it "should use the authenticated node name if no request key is provided" do
64
73
  @request.stubs(:key).returns(nil)
65
74
  Puppet::Node.indirection.expects(:find).with(@name).returns(@node)
@@ -99,6 +108,24 @@ describe Puppet::Resource::Catalog::Compiler do
99
108
  @compiler.find(@request)
100
109
  end
101
110
 
111
+ it "requires `facts_format` option if facts are passed in" do
112
+ facts = Puppet::Node::Facts.new("mynode", :afact => "avalue")
113
+ request = Puppet::Indirector::Request.new(:catalog, :find, "mynode", :facts => facts)
114
+ expect {
115
+ @compiler.find(request)
116
+ }.to raise_error ArgumentError, /no fact format provided for mynode/
117
+ end
118
+
119
+ it "rejects facts in the request from a different node" do
120
+ facts = Puppet::Node::Facts.new("differentnode", :afact => "avalue")
121
+ request = Puppet::Indirector::Request.new(
122
+ :catalog, :find, "mynode", :facts => facts, :facts_format => "unused"
123
+ )
124
+ expect {
125
+ @compiler.find(request)
126
+ }.to raise_error Puppet::Error, /fact definition for the wrong node/i
127
+ end
128
+
102
129
  it "should return the results of compiling as the catalog" do
103
130
  Puppet::Node.indirection.stubs(:find).returns(@node)
104
131
  config = mock 'config'
@@ -133,7 +160,7 @@ describe Puppet::Resource::Catalog::Compiler do
133
160
  before do
134
161
  Facter.stubs(:value).returns "something"
135
162
  @compiler = Puppet::Resource::Catalog::Compiler.new
136
- @request = stub 'request', :options => {}
163
+ @request = Puppet::Indirector::Request.new(:catalog, :find, "hostname", nil)
137
164
 
138
165
  @facts = Puppet::Node::Facts.new('hostname', "fact" => "value", "architecture" => "i386")
139
166
  Puppet::Node::Facts.indirection.stubs(:save).returns(nil)
@@ -40,7 +40,7 @@ shared_examples_for "Indirection Delegator" do
40
40
  end
41
41
  end
42
42
 
43
- request = stub 'request', :key => "me", :options => {}
43
+ request = Puppet::Indirector::Request.new(:indirection, :find, "me", nil)
44
44
 
45
45
  @indirection.stubs(:request).returns request
46
46
 
@@ -101,6 +101,16 @@ shared_examples_for "Delegation Authorizer" do
101
101
  end
102
102
  end
103
103
 
104
+ shared_examples_for "Request validator" do
105
+ it "asks the terminus to validate the request" do
106
+ @terminus.expects(:validate).raises(Puppet::Indirector::ValidationError, "Invalid")
107
+ @terminus.expects(@method).never
108
+ expect {
109
+ @indirection.send(@method, "key")
110
+ }.to raise_error Puppet::Indirector::ValidationError
111
+ end
112
+ end
113
+
104
114
  describe Puppet::Indirector::Indirection do
105
115
  describe "when initializing" do
106
116
  # (LAK) I've no idea how to test this, really.
@@ -141,6 +151,7 @@ describe Puppet::Indirector::Indirection do
141
151
  before :each do
142
152
  @terminus_class = mock 'terminus_class'
143
153
  @terminus = mock 'terminus'
154
+ @terminus.stubs(:validate)
144
155
  @terminus_class.stubs(:new).returns(@terminus)
145
156
  @cache = stub 'cache', :name => "mycache"
146
157
  @cache_class = mock 'cache_class'
@@ -211,6 +222,7 @@ describe Puppet::Indirector::Indirection do
211
222
 
212
223
  it_should_behave_like "Indirection Delegator"
213
224
  it_should_behave_like "Delegation Authorizer"
225
+ it_should_behave_like "Request validator"
214
226
 
215
227
  it "should return the results of the delegation" do
216
228
  @terminus.expects(:find).returns(@instance)
@@ -251,6 +263,7 @@ describe Puppet::Indirector::Indirection do
251
263
  before do
252
264
  @indirection.cache_class = :cache_terminus
253
265
  @cache_class.stubs(:new).returns(@cache)
266
+ @cache.stubs(:validate)
254
267
 
255
268
  @instance.stubs(:expired?).returns false
256
269
  end
@@ -384,6 +397,7 @@ describe Puppet::Indirector::Indirection do
384
397
 
385
398
  it_should_behave_like "Indirection Delegator"
386
399
  it_should_behave_like "Delegation Authorizer"
400
+ it_should_behave_like "Request validator"
387
401
 
388
402
  it "should return true if the head method returned true" do
389
403
  @terminus.expects(:head).returns(true)
@@ -501,6 +515,7 @@ describe Puppet::Indirector::Indirection do
501
515
 
502
516
  it_should_behave_like "Indirection Delegator"
503
517
  it_should_behave_like "Delegation Authorizer"
518
+ it_should_behave_like "Request validator"
504
519
 
505
520
  it "should return the result of removing the instance" do
506
521
  @terminus.stubs(:destroy).returns "yayness"
@@ -539,6 +554,7 @@ describe Puppet::Indirector::Indirection do
539
554
 
540
555
  it_should_behave_like "Indirection Delegator"
541
556
  it_should_behave_like "Delegation Authorizer"
557
+ it_should_behave_like "Request validator"
542
558
 
543
559
  it "should set the expiration date on any instances without one set" do
544
560
  @terminus.stubs(:search).returns([@instance])
@@ -707,6 +723,7 @@ describe Puppet::Indirector::Indirection do
707
723
  before do
708
724
  @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test)
709
725
  @terminus = mock 'terminus'
726
+ @terminus.stubs(:validate)
710
727
  @terminus_class = stub 'terminus class', :new => @terminus
711
728
  end
712
729
 
@@ -1,250 +1,264 @@
1
- #!/usr/bin/env rspec
1
+ #! /usr/bin/env ruby
2
2
  require 'spec_helper'
3
3
  require 'puppet/defaults'
4
4
  require 'puppet/indirector'
5
5
  require 'puppet/indirector/memory'
6
6
 
7
- describe Puppet::Indirector::Terminus, :'fails_on_ruby_1.9.2' => true do
8
- before :each do
9
- Puppet::Indirector::Terminus.stubs(:register_terminus_class)
10
- @indirection = stub 'indirection', :name => :my_stuff, :register_terminus_type => nil
11
- Puppet::Indirector::Indirection.stubs(:instance).with(:my_stuff).returns(@indirection)
12
- @abstract_terminus = Class.new(Puppet::Indirector::Terminus) do
13
- def self.to_s
14
- "Testing::Abstract"
7
+ describe Puppet::Indirector::Terminus do
8
+ before :all do
9
+ class Puppet::AbstractConcept
10
+ extend Puppet::Indirector
11
+ indirects :abstract_concept
12
+ attr_accessor :name
13
+ def initialize(name = "name")
14
+ @name = name
15
15
  end
16
16
  end
17
- @terminus_class = Class.new(@abstract_terminus) do
18
- def self.to_s
19
- "MyStuff::TermType"
20
- end
17
+
18
+ class Puppet::AbstractConcept::Freedom < Puppet::Indirector::Code
21
19
  end
22
- @terminus = @terminus_class.new
23
20
  end
24
21
 
25
- describe Puppet::Indirector::Terminus do
22
+ after :all do
23
+ # Remove the class, unlinking it from the rest of the system.
24
+ Puppet.send(:remove_const, :AbstractConcept)
25
+ end
26
26
 
27
- it "should provide a method for setting terminus class documentation" do
28
- @terminus_class.should respond_to(:desc)
29
- end
27
+ let :terminus_class do Puppet::AbstractConcept::Freedom end
28
+ let :terminus do terminus_class.new end
29
+ let :indirection do Puppet::AbstractConcept.indirection end
30
+ let :model do Puppet::AbstractConcept end
30
31
 
31
- it "should support a class-level name attribute" do
32
- @terminus_class.should respond_to(:name)
33
- end
32
+ it "should provide a method for setting terminus class documentation" do
33
+ terminus_class.should respond_to(:desc)
34
+ end
34
35
 
35
- it "should support a class-level indirection attribute" do
36
- @terminus_class.should respond_to(:indirection)
37
- end
36
+ it "should support a class-level name attribute" do
37
+ terminus_class.should respond_to(:name)
38
+ end
38
39
 
39
- it "should support a class-level terminus-type attribute" do
40
- @terminus_class.should respond_to(:terminus_type)
41
- end
40
+ it "should support a class-level indirection attribute" do
41
+ terminus_class.should respond_to(:indirection)
42
+ end
42
43
 
43
- it "should support a class-level model attribute" do
44
- @terminus_class.should respond_to(:model)
45
- end
44
+ it "should support a class-level terminus-type attribute" do
45
+ terminus_class.should respond_to(:terminus_type)
46
+ end
46
47
 
47
- it "should accept indirection instances as its indirection" do
48
- indirection = stub 'indirection', :is_a? => true, :register_terminus_type => nil
49
- proc { @terminus_class.indirection = indirection }.should_not raise_error
50
- @terminus_class.indirection.should equal(indirection)
51
- end
48
+ it "should support a class-level model attribute" do
49
+ terminus_class.should respond_to(:model)
50
+ end
52
51
 
53
- it "should look up indirection instances when only a name has been provided" do
54
- indirection = mock 'indirection'
55
- Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns(indirection)
56
- @terminus_class.indirection = :myind
57
- @terminus_class.indirection.should equal(indirection)
58
- end
52
+ it "should accept indirection instances as its indirection" do
53
+ # The test is that this shouldn't raise, and should preserve the object
54
+ # instance exactly, hence "equal", not just "==".
55
+ terminus_class.indirection = indirection
56
+ terminus_class.indirection.should equal indirection
57
+ end
59
58
 
60
- it "should fail when provided a name that does not resolve to an indirection" do
61
- Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns(nil)
62
- proc { @terminus_class.indirection = :myind }.should raise_error(ArgumentError)
59
+ it "should look up indirection instances when only a name has been provided" do
60
+ terminus_class.indirection = :abstract_concept
61
+ terminus_class.indirection.should equal indirection
62
+ end
63
63
 
64
- # It shouldn't overwrite our existing one (or, more normally, it shouldn't set
65
- # anything).
66
- @terminus_class.indirection.should equal(@indirection)
67
- end
64
+ it "should fail when provided a name that does not resolve to an indirection" do
65
+ expect {
66
+ terminus_class.indirection = :exploding_whales
67
+ }.to raise_error(ArgumentError, /Could not find indirection instance/)
68
+
69
+ # We should still have the default indirection.
70
+ terminus_class.indirection.should equal indirection
68
71
  end
69
72
 
70
- describe Puppet::Indirector::Terminus, " when creating terminus classes" do
71
- it "should associate the subclass with an indirection based on the subclass constant" do
72
- @terminus.indirection.should equal(@indirection)
73
+ describe "when a terminus instance" do
74
+ it "should return the class's name as its name" do
75
+ terminus.name.should == :freedom
73
76
  end
74
77
 
75
- it "should set the subclass's type to the abstract terminus name" do
76
- @terminus.terminus_type.should == :abstract
78
+ it "should return the class's indirection as its indirection" do
79
+ terminus.indirection.should equal indirection
77
80
  end
78
81
 
79
- it "should set the subclass's name to the indirection name" do
80
- @terminus.name.should == :term_type
82
+ it "should set the instances's type to the abstract terminus type's name" do
83
+ terminus.terminus_type.should == :code
81
84
  end
82
85
 
83
- it "should set the subclass's model to the indirection model" do
84
- @indirection.expects(:model).returns :yay
85
- @terminus.model.should == :yay
86
+ it "should set the instances's model to the indirection's model" do
87
+ terminus.model.should equal indirection.model
86
88
  end
87
89
  end
88
90
 
89
- describe Puppet::Indirector::Terminus, " when a terminus instance" do
91
+ describe "when managing terminus classes" do
92
+ it "should provide a method for registering terminus classes" do
93
+ Puppet::Indirector::Terminus.should respond_to(:register_terminus_class)
94
+ end
90
95
 
91
- it "should return the class's name as its name" do
92
- @terminus.name.should == :term_type
96
+ it "should provide a method for returning terminus classes by name and type" do
97
+ terminus = stub 'terminus_type', :name => :abstract, :indirection_name => :whatever
98
+ Puppet::Indirector::Terminus.register_terminus_class(terminus)
99
+ Puppet::Indirector::Terminus.terminus_class(:whatever, :abstract).should equal(terminus)
93
100
  end
94
101
 
95
- it "should return the class's indirection as its indirection" do
96
- @terminus.indirection.should equal(@indirection)
102
+ it "should set up autoloading for any terminus class types requested" do
103
+ Puppet::Indirector::Terminus.expects(:instance_load).with(:test2, "puppet/indirector/test2")
104
+ Puppet::Indirector::Terminus.terminus_class(:test2, :whatever)
97
105
  end
98
106
 
99
- it "should set the instances's type to the abstract terminus type's name" do
100
- @terminus.terminus_type.should == :abstract
107
+ it "should load terminus classes that are not found" do
108
+ # Set up instance loading; it would normally happen automatically
109
+ Puppet::Indirector::Terminus.instance_load :test1, "puppet/indirector/test1"
110
+
111
+ Puppet::Indirector::Terminus.instance_loader(:test1).expects(:load).with(:yay)
112
+ Puppet::Indirector::Terminus.terminus_class(:test1, :yay)
101
113
  end
102
114
 
103
- it "should set the instances's model to the indirection's model" do
104
- @indirection.expects(:model).returns :yay
105
- @terminus.model.should == :yay
115
+ it "should fail when no indirection can be found" do
116
+ Puppet::Indirector::Indirection.expects(:instance).with(:abstract_concept).returns(nil)
117
+ expect {
118
+ class Puppet::AbstractConcept::Physics < Puppet::Indirector::Code
119
+ end
120
+ }.to raise_error(ArgumentError, /Could not find indirection instance/)
106
121
  end
107
- end
108
- end
109
122
 
110
- # LAK: This could reasonably be in the Indirection instances, too. It doesn't make
111
- # a whole heckuva lot of difference, except that with the instance loading in
112
- # the Terminus base class, we have to have a check to see if we're already
113
- # instance-loading a given terminus class type.
114
- describe Puppet::Indirector::Terminus, " when managing terminus classes" do
115
- it "should provide a method for registering terminus classes" do
116
- Puppet::Indirector::Terminus.should respond_to(:register_terminus_class)
117
- end
123
+ it "should register the terminus class with the terminus base class" do
124
+ Puppet::Indirector::Terminus.expects(:register_terminus_class).with do |type|
125
+ type.indirection_name == :abstract_concept and type.name == :intellect
126
+ end
118
127
 
119
- it "should provide a method for returning terminus classes by name and type" do
120
- terminus = stub 'terminus_type', :name => :abstract, :indirection_name => :whatever
121
- Puppet::Indirector::Terminus.register_terminus_class(terminus)
122
- Puppet::Indirector::Terminus.terminus_class(:whatever, :abstract).should equal(terminus)
128
+ begin
129
+ class Puppet::AbstractConcept::Intellect < Puppet::Indirector::Code
130
+ end
131
+ ensure
132
+ Puppet::AbstractConcept.send(:remove_const, :Intellect) rescue nil
133
+ end
134
+ end
123
135
  end
124
136
 
125
- it "should set up autoloading for any terminus class types requested" do
126
- Puppet::Indirector::Terminus.expects(:instance_load).with(:test2, "puppet/indirector/test2")
127
- Puppet::Indirector::Terminus.terminus_class(:test2, :whatever)
128
- end
137
+ describe "when parsing class constants for indirection and terminus names" do
138
+ before :each do
139
+ Puppet::Indirector::Terminus.stubs(:register_terminus_class)
140
+ end
129
141
 
130
- it "should load terminus classes that are not found" do
131
- # Set up instance loading; it would normally happen automatically
132
- Puppet::Indirector::Terminus.instance_load :test1, "puppet/indirector/test1"
142
+ let :subclass do
143
+ subclass = mock 'subclass'
144
+ subclass.stubs(:to_s).returns("TestInd::OneTwo")
145
+ subclass.stubs(:mark_as_abstract_terminus)
146
+ subclass
147
+ end
133
148
 
134
- Puppet::Indirector::Terminus.instance_loader(:test1).expects(:load).with(:yay)
135
- Puppet::Indirector::Terminus.terminus_class(:test1, :yay)
136
- end
149
+ it "should fail when anonymous classes are used" do
150
+ expect {
151
+ Puppet::Indirector::Terminus.inherited(Class.new)
152
+ }.to raise_error(Puppet::DevError, /Terminus subclasses must have associated constants/)
153
+ end
137
154
 
138
- it "should fail when no indirection can be found", :'fails_on_ruby_1.9.2' => true do
139
- Puppet::Indirector::Indirection.expects(:instance).with(:my_indirection).returns(nil)
155
+ it "should use the last term in the constant for the terminus class name" do
156
+ subclass.expects(:name=).with(:one_two)
157
+ subclass.stubs(:indirection=)
158
+ Puppet::Indirector::Terminus.inherited(subclass)
159
+ end
140
160
 
141
- @abstract_terminus = Class.new(Puppet::Indirector::Terminus) do
142
- def self.to_s
143
- "Abstract"
144
- end
161
+ it "should convert the terminus name to a downcased symbol" do
162
+ subclass.expects(:name=).with(:one_two)
163
+ subclass.stubs(:indirection=)
164
+ Puppet::Indirector::Terminus.inherited(subclass)
145
165
  end
146
- proc {
147
- @terminus = Class.new(@abstract_terminus) do
148
- def self.to_s
149
- "MyIndirection::TestType"
150
- end
151
- end
152
- }.should raise_error(ArgumentError)
153
- end
154
166
 
155
- it "should register the terminus class with the terminus base class", :'fails_on_ruby_1.9.2' => true do
156
- Puppet::Indirector::Terminus.expects(:register_terminus_class).with do |type|
157
- type.indirection_name == :my_indirection and type.name == :test_terminus
167
+ it "should use the second to last term in the constant for the indirection name" do
168
+ subclass.expects(:indirection=).with(:test_ind)
169
+ subclass.stubs(:name=)
170
+ subclass.stubs(:terminus_type=)
171
+ Puppet::Indirector::Memory.inherited(subclass)
158
172
  end
159
- @indirection = stub 'indirection', :name => :my_indirection, :register_terminus_type => nil
160
- Puppet::Indirector::Indirection.expects(:instance).with(:my_indirection).returns(@indirection)
161
173
 
162
- @abstract_terminus = Class.new(Puppet::Indirector::Terminus) do
163
- def self.to_s
164
- "Abstract"
165
- end
174
+ it "should convert the indirection name to a downcased symbol" do
175
+ subclass.expects(:indirection=).with(:test_ind)
176
+ subclass.stubs(:name=)
177
+ subclass.stubs(:terminus_type=)
178
+ Puppet::Indirector::Memory.inherited(subclass)
166
179
  end
167
180
 
168
- @terminus = Class.new(@abstract_terminus) do
169
- def self.to_s
170
- "MyIndirection::TestTerminus"
171
- end
181
+ it "should convert camel case to lower case with underscores as word separators" do
182
+ subclass.expects(:name=).with(:one_two)
183
+ subclass.stubs(:indirection=)
184
+
185
+ Puppet::Indirector::Terminus.inherited(subclass)
172
186
  end
173
187
  end
174
- end
175
188
 
176
- describe Puppet::Indirector::Terminus, " when parsing class constants for indirection and terminus names" do
177
- before do
178
- @subclass = mock 'subclass'
179
- @subclass.stubs(:to_s).returns("TestInd::OneTwo")
180
- @subclass.stubs(:mark_as_abstract_terminus)
181
- Puppet::Indirector::Terminus.stubs(:register_terminus_class)
182
- end
189
+ describe "when creating terminus class types" do
190
+ before :all do
191
+ Puppet::Indirector::Terminus.stubs(:register_terminus_class)
183
192
 
184
- it "should fail when anonymous classes are used" do
185
- proc { Puppet::Indirector::Terminus.inherited(Class.new) }.should raise_error(Puppet::DevError)
186
- end
193
+ class Puppet::Indirector::Terminus::TestTerminusType < Puppet::Indirector::Terminus
194
+ end
195
+ end
187
196
 
188
- it "should use the last term in the constant for the terminus class name" do
189
- @subclass.expects(:name=).with(:one_two)
190
- @subclass.stubs(:indirection=)
191
- Puppet::Indirector::Terminus.inherited(@subclass)
192
- end
197
+ after :all do
198
+ Puppet::Indirector::Terminus.send(:remove_const, :TestTerminusType)
199
+ end
193
200
 
194
- it "should convert the terminus name to a downcased symbol" do
195
- @subclass.expects(:name=).with(:one_two)
196
- @subclass.stubs(:indirection=)
197
- Puppet::Indirector::Terminus.inherited(@subclass)
198
- end
201
+ let :subclass do
202
+ Puppet::Indirector::Terminus::TestTerminusType
203
+ end
204
+
205
+ it "should set the name of the abstract subclass to be its class constant" do
206
+ subclass.name.should == :test_terminus_type
207
+ end
208
+
209
+ it "should mark abstract terminus types as such" do
210
+ subclass.should be_abstract_terminus
211
+ end
199
212
 
200
- it "should use the second to last term in the constant for the indirection name" do
201
- @subclass.expects(:indirection=).with(:test_ind)
202
- @subclass.stubs(:name=)
203
- @subclass.stubs(:terminus_type=)
204
- Puppet::Indirector::Memory.inherited(@subclass)
213
+ it "should not allow instances of abstract subclasses to be created" do
214
+ expect { subclass.new }.to raise_error(Puppet::DevError)
215
+ end
205
216
  end
206
217
 
207
- it "should convert the indirection name to a downcased symbol" do
208
- @subclass.expects(:indirection=).with(:test_ind)
209
- @subclass.stubs(:name=)
210
- @subclass.stubs(:terminus_type=)
211
- Puppet::Indirector::Memory.inherited(@subclass)
218
+ describe "when listing terminus classes" do
219
+ it "should list the terminus files available to load" do
220
+ Puppet::Util::Autoload.any_instance.stubs(:files_to_load).returns ["/foo/bar/baz", "/max/runs/marathon"]
221
+ Puppet::Indirector::Terminus.terminus_classes('my_stuff').should == [:baz, :marathon]
222
+ end
212
223
  end
213
224
 
214
- it "should convert camel case to lower case with underscores as word separators" do
215
- @subclass.expects(:name=).with(:one_two)
216
- @subclass.stubs(:indirection=)
225
+ describe "when validating a request" do
226
+ let :request do
227
+ Puppet::Indirector::Request.new(indirection.name, :find, "the_key", instance)
228
+ end
217
229
 
218
- Puppet::Indirector::Terminus.inherited(@subclass)
219
- end
220
- end
230
+ describe "`instance.name` does not match the key in the request" do
231
+ let(:instance) { model.new("wrong_key") }
221
232
 
222
- describe Puppet::Indirector::Terminus, " when creating terminus class types", :'fails_on_ruby_1.9.2' => true do
223
- before do
224
- Puppet::Indirector::Terminus.stubs(:register_terminus_class)
225
- @subclass = Class.new(Puppet::Indirector::Terminus) do
226
- def self.to_s
227
- "Puppet::Indirector::Terminus::MyTermType"
233
+ it "raises an error " do
234
+ expect {
235
+ terminus.validate(request)
236
+ }.to raise_error(
237
+ Puppet::Indirector::ValidationError,
238
+ /Instance name .* does not match requested key/
239
+ )
228
240
  end
229
241
  end
230
- end
231
242
 
232
- it "should set the name of the abstract subclass to be its class constant" do
233
- @subclass.name.should equal(:my_term_type)
234
- end
243
+ describe "`instance` is not an instance of the model class" do
244
+ let(:instance) { mock "instance" }
235
245
 
236
- it "should mark abstract terminus types as such" do
237
- @subclass.should be_abstract_terminus
238
- end
246
+ it "raises an error" do
247
+ expect {
248
+ terminus.validate(request)
249
+ }.to raise_error(
250
+ Puppet::Indirector::ValidationError,
251
+ /Invalid instance type/
252
+ )
253
+ end
254
+ end
239
255
 
240
- it "should not allow instances of abstract subclasses to be created" do
241
- proc { @subclass.new }.should raise_error(Puppet::DevError)
242
- end
243
- end
256
+ describe "the instance key and class match the request key and model class" do
257
+ let(:instance) { model.new("the_key") }
244
258
 
245
- describe Puppet::Indirector::Terminus, " when listing terminus classes" do
246
- it "should list the terminus files available to load" do
247
- Puppet::Util::Autoload.any_instance.stubs(:files_to_load).returns ["/foo/bar/baz", "/max/runs/marathon"]
248
- Puppet::Indirector::Terminus.terminus_classes('my_stuff').should == [:baz, :marathon]
259
+ it "passes" do
260
+ terminus.validate(request)
261
+ end
262
+ end
249
263
  end
250
264
  end