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.
- data/CHANGELOG +226 -0
- data/conf/auth.conf +3 -3
- data/ext/packaging/README.md +191 -57
- data/ext/packaging/spec/spec_helper.rb +2 -2
- data/ext/packaging/spec/tasks/00_utils_spec.rb +63 -18
- data/ext/packaging/spec/tasks/build_object_spec.rb +171 -0
- data/ext/packaging/tasks/00_utils.rake +186 -33
- data/ext/packaging/tasks/10_setupvars.rake +94 -65
- data/ext/packaging/tasks/20_setupextravars.rake +45 -26
- data/ext/packaging/tasks/30_metrics.rake +41 -0
- data/ext/packaging/tasks/apple.rake +92 -36
- data/ext/packaging/tasks/build.rake +183 -0
- data/ext/packaging/tasks/deb.rake +45 -40
- data/ext/packaging/tasks/deb_repos.rake +103 -0
- data/ext/packaging/tasks/doc.rake +5 -5
- data/ext/packaging/tasks/fetch.rake +35 -10
- data/ext/packaging/tasks/gem.rake +38 -27
- data/ext/packaging/tasks/ips.rake +14 -14
- data/ext/packaging/tasks/jenkins.rake +337 -0
- data/ext/packaging/tasks/mock.rake +153 -72
- data/ext/packaging/tasks/pe_deb.rake +2 -2
- data/ext/packaging/tasks/pe_remote.rake +22 -19
- data/ext/packaging/tasks/pe_rpm.rake +5 -5
- data/ext/packaging/tasks/pe_ship.rake +31 -21
- data/ext/packaging/tasks/pe_sign.rake +20 -19
- data/ext/packaging/tasks/pe_sles.rake +40 -36
- data/ext/packaging/tasks/pe_tar.rake +5 -0
- data/ext/packaging/tasks/release.rake +32 -12
- data/ext/packaging/tasks/remote_build.rake +141 -83
- data/ext/packaging/tasks/retrieve.rake +23 -0
- data/ext/packaging/tasks/rpm.rake +11 -19
- data/ext/packaging/tasks/rpm_repos.rake +127 -0
- data/ext/packaging/tasks/ship.rake +68 -55
- data/ext/packaging/tasks/sign.rake +38 -10
- data/ext/packaging/tasks/tar.rake +25 -9
- data/ext/packaging/tasks/update.rake +2 -2
- data/ext/packaging/tasks/version.rake +34 -14
- data/ext/packaging/tasks/z_data_dump.rake +33 -0
- data/lib/puppet/indirector/catalog/compiler.rb +13 -2
- data/lib/puppet/indirector/certificate_status/file.rb +5 -0
- data/lib/puppet/indirector/errors.rb +5 -0
- data/lib/puppet/indirector/file_bucket_file/file.rb +4 -0
- data/lib/puppet/indirector/file_bucket_file/selector.rb +4 -0
- data/lib/puppet/indirector/indirection.rb +1 -0
- data/lib/puppet/indirector/resource/active_record.rb +3 -0
- data/lib/puppet/indirector/resource/ral.rb +4 -0
- data/lib/puppet/indirector/resource/store_configs.rb +3 -0
- data/lib/puppet/indirector/resource/validator.rb +8 -0
- data/lib/puppet/indirector/rest.rb +8 -0
- data/lib/puppet/indirector/run/local.rb +4 -0
- data/lib/puppet/indirector/terminus.rb +20 -0
- data/lib/puppet/network/formats.rb +3 -3
- data/lib/puppet/network/handler/master.rb +1 -1
- data/lib/puppet/network/handler/report.rb +1 -1
- data/lib/puppet/network/http/handler.rb +7 -1
- data/lib/puppet/network/http/rack/rest.rb +7 -2
- data/lib/puppet/network/http/webrick.rb +1 -0
- data/lib/puppet/network/rest_authconfig.rb +1 -1
- data/lib/puppet/parser/templatewrapper.rb +17 -17
- data/lib/puppet/util/monkey_patches.rb +58 -0
- data/lib/puppet/version.rb +1 -1
- data/spec/integration/indirector/catalog/compiler_spec.rb +1 -0
- data/spec/integration/indirector/catalog/queue_spec.rb +1 -1
- data/spec/integration/resource/catalog_spec.rb +1 -0
- data/spec/unit/indirector/catalog/compiler_spec.rb +29 -2
- data/spec/unit/indirector/indirection_spec.rb +18 -1
- data/spec/unit/indirector/terminus_spec.rb +191 -177
- data/spec/unit/network/formats_spec.rb +6 -6
- data/spec/unit/network/http/handler_spec.rb +25 -0
- data/spec/unit/network/http/rack/rest_spec.rb +17 -0
- data/spec/unit/network/http/webrick_spec.rb +4 -0
- data/spec/unit/network/http_pool_spec.rb +0 -1
- data/spec/unit/network/rest_authconfig_spec.rb +16 -1
- data/spec/unit/parser/functions/inline_template_spec.rb +13 -0
- data/spec/unit/parser/functions/template_spec.rb +15 -0
- data/spec/unit/parser/templatewrapper_spec.rb +19 -4
- data/spec/unit/ssl/certificate_request_spec.rb +2 -0
- data/spec/unit/ssl/host_spec.rb +1 -0
- data/spec/unit/util/monkey_patches_spec.rb +12 -0
- data/test/language/snippets.rb +1 -1
- 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 => "
|
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 =~ /#{
|
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 =>
|
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 =>
|
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}'"
|
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 @
|
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(
|
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
|
-
|
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
|
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(
|
105
|
-
template.filename =
|
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[#{(
|
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
|
data/lib/puppet/version.rb
CHANGED
@@ -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 =
|
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 =
|
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
|
-
|
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
|
8
|
-
before :
|
9
|
-
Puppet::
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
def
|
14
|
-
|
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
|
-
|
18
|
-
|
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
|
-
|
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
|
-
|
28
|
-
|
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
|
-
|
32
|
-
|
33
|
-
|
32
|
+
it "should provide a method for setting terminus class documentation" do
|
33
|
+
terminus_class.should respond_to(:desc)
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
it "should support a class-level name attribute" do
|
37
|
+
terminus_class.should respond_to(:name)
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
it "should support a class-level indirection attribute" do
|
41
|
+
terminus_class.should respond_to(:indirection)
|
42
|
+
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
44
|
+
it "should support a class-level terminus-type attribute" do
|
45
|
+
terminus_class.should respond_to(:terminus_type)
|
46
|
+
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
71
|
-
it "should
|
72
|
-
|
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
|
76
|
-
|
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
|
80
|
-
|
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
|
84
|
-
|
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
|
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
|
92
|
-
|
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
|
96
|
-
|
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
|
100
|
-
|
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
|
104
|
-
|
105
|
-
|
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
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
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
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
131
|
-
|
132
|
-
|
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
|
-
|
135
|
-
|
136
|
-
|
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
|
-
|
139
|
-
|
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
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
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
|
-
|
156
|
-
|
157
|
-
|
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
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
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
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
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
|
177
|
-
|
178
|
-
|
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
|
-
|
185
|
-
|
186
|
-
|
193
|
+
class Puppet::Indirector::Terminus::TestTerminusType < Puppet::Indirector::Terminus
|
194
|
+
end
|
195
|
+
end
|
187
196
|
|
188
|
-
|
189
|
-
|
190
|
-
|
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
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
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
|
-
|
201
|
-
|
202
|
-
|
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
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
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
|
-
|
215
|
-
|
216
|
-
|
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
|
-
|
219
|
-
|
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
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
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
|
-
|
233
|
-
|
234
|
-
end
|
243
|
+
describe "`instance` is not an instance of the model class" do
|
244
|
+
let(:instance) { mock "instance" }
|
235
245
|
|
236
|
-
|
237
|
-
|
238
|
-
|
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
|
-
|
241
|
-
|
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
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
259
|
+
it "passes" do
|
260
|
+
terminus.validate(request)
|
261
|
+
end
|
262
|
+
end
|
249
263
|
end
|
250
264
|
end
|