puppet 6.13.0 → 6.14.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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +7 -13
  3. data/Gemfile.lock +6 -6
  4. data/README.md +15 -22
  5. data/lib/puppet.rb +1 -1
  6. data/lib/puppet/application/agent.rb +9 -11
  7. data/lib/puppet/application/describe.rb +7 -5
  8. data/lib/puppet/application/device.rb +2 -2
  9. data/lib/puppet/application/filebucket.rb +14 -1
  10. data/lib/puppet/application/ssl.rb +1 -1
  11. data/lib/puppet/configurer.rb +30 -41
  12. data/lib/puppet/configurer/plugin_handler.rb +10 -1
  13. data/lib/puppet/defaults.rb +7 -1
  14. data/lib/puppet/face/plugin.rb +1 -1
  15. data/lib/puppet/functions/eyaml_lookup_key.rb +13 -8
  16. data/lib/puppet/http.rb +1 -0
  17. data/lib/puppet/http/client.rb +69 -34
  18. data/lib/puppet/http/resolver/server_list.rb +2 -2
  19. data/lib/puppet/http/resolver/settings.rb +1 -1
  20. data/lib/puppet/http/resolver/srv.rb +1 -1
  21. data/lib/puppet/http/response.rb +6 -1
  22. data/lib/puppet/http/service.rb +30 -11
  23. data/lib/puppet/http/service/ca.rb +8 -8
  24. data/lib/puppet/http/service/compiler.rb +41 -10
  25. data/lib/puppet/http/service/file_server.rb +40 -20
  26. data/lib/puppet/http/service/report.rb +12 -15
  27. data/lib/puppet/http/session.rb +39 -1
  28. data/lib/puppet/indirector/catalog/rest.rb +33 -0
  29. data/lib/puppet/indirector/facts/rest.rb +41 -0
  30. data/lib/puppet/indirector/file_content/rest.rb +30 -0
  31. data/lib/puppet/indirector/file_metadata/rest.rb +50 -0
  32. data/lib/puppet/indirector/node/rest.rb +23 -0
  33. data/lib/puppet/indirector/report/rest.rb +19 -0
  34. data/lib/puppet/indirector/rest.rb +6 -0
  35. data/lib/puppet/indirector/status/rest.rb +17 -0
  36. data/lib/puppet/loaders.rb +6 -0
  37. data/lib/puppet/network/http/base_pool.rb +1 -1
  38. data/lib/puppet/network/http/pool.rb +6 -1
  39. data/lib/puppet/provider/group/groupadd.rb +9 -4
  40. data/lib/puppet/runtime.rb +8 -1
  41. data/lib/puppet/settings.rb +2 -0
  42. data/lib/puppet/settings/http_extra_headers_setting.rb +25 -0
  43. data/lib/puppet/ssl/state_machine.rb +4 -0
  44. data/lib/puppet/test/test_helper.rb +3 -1
  45. data/lib/puppet/type/file.rb +13 -0
  46. data/lib/puppet/type/file/source.rb +47 -58
  47. data/lib/puppet/version.rb +1 -1
  48. data/locales/puppet.pot +167 -160
  49. data/man/man5/puppet.conf.5 +11 -3
  50. data/man/man8/puppet-agent.8 +6 -6
  51. data/man/man8/puppet-apply.8 +1 -1
  52. data/man/man8/puppet-catalog.8 +1 -1
  53. data/man/man8/puppet-config.8 +1 -1
  54. data/man/man8/puppet-describe.8 +1 -1
  55. data/man/man8/puppet-device.8 +2 -2
  56. data/man/man8/puppet-doc.8 +1 -1
  57. data/man/man8/puppet-epp.8 +1 -1
  58. data/man/man8/puppet-facts.8 +1 -1
  59. data/man/man8/puppet-filebucket.8 +17 -2
  60. data/man/man8/puppet-generate.8 +1 -1
  61. data/man/man8/puppet-help.8 +1 -1
  62. data/man/man8/puppet-key.8 +1 -1
  63. data/man/man8/puppet-lookup.8 +1 -1
  64. data/man/man8/puppet-man.8 +1 -1
  65. data/man/man8/puppet-module.8 +1 -1
  66. data/man/man8/puppet-node.8 +1 -1
  67. data/man/man8/puppet-parser.8 +1 -1
  68. data/man/man8/puppet-plugin.8 +1 -1
  69. data/man/man8/puppet-report.8 +1 -1
  70. data/man/man8/puppet-resource.8 +1 -1
  71. data/man/man8/puppet-script.8 +1 -1
  72. data/man/man8/puppet-ssl.8 +2 -2
  73. data/man/man8/puppet-status.8 +1 -1
  74. data/man/man8/puppet.8 +2 -2
  75. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_fetch_if_not_on_the_local_disk.yml +1 -67
  76. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_not_update_if_content_on_disk_is_up-to-date.yml +1 -69
  77. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_update_if_content_differs_on_disk.yml +1 -69
  78. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_mtime_is_older_on_disk.yml +1 -67
  79. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_no_header_specified.yml +1 -65
  80. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_not_on_the_local_disk.yml +1 -67
  81. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_not_update_if_mtime_is_newer_on_disk.yml +1 -67
  82. data/spec/integration/faces/plugin_spec.rb +3 -1
  83. data/spec/integration/http/client_spec.rb +11 -0
  84. data/spec/integration/network/http_pool_spec.rb +9 -1
  85. data/spec/unit/application/describe_spec.rb +88 -50
  86. data/spec/unit/configurer/plugin_handler_spec.rb +36 -19
  87. data/spec/unit/configurer_spec.rb +16 -14
  88. data/spec/unit/face/plugin_spec.rb +12 -10
  89. data/spec/unit/functions/lookup_spec.rb +13 -0
  90. data/spec/unit/http/client_spec.rb +172 -1
  91. data/spec/unit/http/resolver_spec.rb +14 -2
  92. data/spec/unit/http/response_spec.rb +69 -0
  93. data/spec/unit/http/service/ca_spec.rb +28 -9
  94. data/spec/unit/http/service/compiler_spec.rb +151 -24
  95. data/spec/unit/http/service/file_server_spec.rb +65 -8
  96. data/spec/unit/http/service/report_spec.rb +17 -8
  97. data/spec/unit/http/service_spec.rb +92 -3
  98. data/spec/unit/http/session_spec.rb +104 -1
  99. data/spec/unit/indirector/catalog/rest_spec.rb +59 -2
  100. data/spec/unit/indirector/facts/rest_spec.rb +79 -24
  101. data/spec/unit/indirector/file_content/rest_spec.rb +53 -2
  102. data/spec/unit/indirector/file_metadata/rest_spec.rb +109 -2
  103. data/spec/unit/indirector/node/rest_spec.rb +57 -2
  104. data/spec/unit/indirector/report/rest_spec.rb +58 -51
  105. data/spec/unit/indirector/resource/ral_spec.rb +7 -8
  106. data/spec/unit/indirector/status/rest_spec.rb +43 -2
  107. data/spec/unit/network/http/pool_spec.rb +57 -11
  108. data/spec/unit/provider/group/groupadd_spec.rb +22 -8
  109. data/spec/unit/settings/autosign_setting_spec.rb +1 -1
  110. data/spec/unit/settings/http_extra_headers_spec.rb +64 -0
  111. data/spec/unit/ssl/state_machine_spec.rb +10 -0
  112. data/spec/unit/transaction_spec.rb +0 -2
  113. data/spec/unit/type/file/ensure_spec.rb +1 -2
  114. data/spec/unit/type/file/source_spec.rb +86 -35
  115. data/spec/unit/util/at_fork_spec.rb +1 -0
  116. data/spec/unit/util/pidlock_spec.rb +36 -24
  117. metadata +7 -3
  118. data/COMMITTERS.md +0 -244
@@ -27,14 +27,6 @@ describe Puppet::HTTP::Service::FileServer do
27
27
 
28
28
  subject.get_file_content(path: '/:mount/:path', environment: environment) { |data| }
29
29
  end
30
-
31
- it 'includes the X-Puppet-Profiling header when Puppet[:profile] is true' do
32
- stub_request(:get, uri).with(headers: {'X-Puppet-Version' => /./, 'User-Agent' => /./, 'X-Puppet-Profiling' => 'true'})
33
-
34
- Puppet[:profile] = true
35
-
36
- subject.get_file_content(path: '/:mount/:path', environment: environment) { |data| }
37
- end
38
30
  end
39
31
 
40
32
  context 'when routing to the file service' do
@@ -54,6 +46,16 @@ describe Puppet::HTTP::Service::FileServer do
54
46
  let(:filemetadata) { Puppet::FileServing::Metadata.new(path) }
55
47
  let(:request_path) { "/:mount/#{path}"}
56
48
 
49
+ it 'includes puppet headers set via the :http_extra_headers and :profile settings' do
50
+ stub_request(:get, url).with(headers: {'Example-Header' => 'real-thing', 'another' => 'thing', 'X-Puppet-Profiling' => 'true'}).
51
+ to_return(status: 200, body: filemetadata.render, headers: { 'Content-Type' => 'application/json' })
52
+
53
+ Puppet[:http_extra_headers] = 'Example-Header:real-thing,another:thing'
54
+ Puppet[:profile] = true
55
+
56
+ subject.get_file_metadata(path: request_path, environment: environment)
57
+ end
58
+
57
59
  it 'submits a request for file metadata to the server' do
58
60
  stub_request(:get, url).with(
59
61
  headers: {'Accept'=>'application/json, application/x-msgpack, text/pson',}
@@ -117,6 +119,16 @@ describe Puppet::HTTP::Service::FileServer do
117
119
  let(:formatter) { Puppet::Network::FormatHandler.format(:json) }
118
120
  let(:request_path) { "/:mount/#{path}"}
119
121
 
122
+ it 'includes puppet headers set via the :http_extra_headers and :profile settings' do
123
+ stub_request(:get, url).with(headers: {'Example-Header' => 'real-thing', 'another' => 'thing', 'X-Puppet-Profiling' => 'true'}).
124
+ to_return(status: 200, body: formatter.render_multiple(filemetadatas), headers: { 'Content-Type' => 'application/json' })
125
+
126
+ Puppet[:http_extra_headers] = 'Example-Header:real-thing,another:thing'
127
+ Puppet[:profile] = true
128
+
129
+ subject.get_file_metadatas(path: request_path, environment: environment)
130
+ end
131
+
120
132
  it 'submits a request for file metadata to the server' do
121
133
  stub_request(:get, url).with(
122
134
  headers: {'Accept'=>'application/json, application/x-msgpack, text/pson',}
@@ -188,6 +200,18 @@ describe Puppet::HTTP::Service::FileServer do
188
200
  context 'getting file content' do
189
201
  let(:uri) {"https://www.example.com:443/puppet/v3/file_content/:mount/:path?environment=testing"}
190
202
 
203
+ it 'includes puppet headers set via the :http_extra_headers and :profile settings' do
204
+ stub_request(:get, uri).with(headers: {'Example-Header' => 'real-thing', 'another' => 'thing', 'X-Puppet-Profiling' => 'true'}).
205
+ to_return(status: 200, body: "and beyond")
206
+
207
+ Puppet[:http_extra_headers] = 'Example-Header:real-thing,another:thing'
208
+ Puppet[:profile] = true
209
+
210
+ expect { |b|
211
+ subject.get_file_content(path: '/:mount/:path', environment: environment, &b)
212
+ }.to yield_with_args("and beyond")
213
+ end
214
+
191
215
  it 'yields file content' do
192
216
  stub_request(:get, uri).with do |request|
193
217
  expect(request.headers).to include({'Accept' => 'application/octet-stream'})
@@ -216,4 +240,37 @@ describe Puppet::HTTP::Service::FileServer do
216
240
  }.to raise_error(ArgumentError, 'Path must start with a slash')
217
241
  end
218
242
  end
243
+
244
+ context 'getting static file content' do
245
+ let(:code_id) { "0fc72115-adc6-4b1a-aa50-8f31b3ece440" }
246
+ let(:uri) { "https://www.example.com:443/puppet/v3/static_file_content/:mount/:path?environment=testing&code_id=#{code_id}"}
247
+
248
+ it 'yields file content' do
249
+ stub_request(:get, uri).with do |request|
250
+ expect(request.headers).to include({'Accept' => 'application/octet-stream'})
251
+ end.to_return(status: 200, body: "and beyond")
252
+
253
+ expect { |b|
254
+ subject.get_static_file_content(path: '/:mount/:path', environment: environment, code_id: code_id, &b)
255
+ }.to yield_with_args("and beyond")
256
+ end
257
+
258
+ it 'raises response error if unsuccessful' do
259
+ stub_request(:get, uri).to_return(status: [400, 'Bad Request'])
260
+
261
+ expect {
262
+ subject.get_static_file_content(path: '/:mount/:path', environment: environment, code_id: code_id) { |data| }
263
+ }.to raise_error do |err|
264
+ expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
265
+ expect(err.message).to eq('Bad Request')
266
+ expect(err.response.code).to eq(400)
267
+ end
268
+ end
269
+
270
+ it 'raises response error if path is relative' do
271
+ expect {
272
+ subject.get_static_file_content(path: 'relative_path', environment: environment, code_id: code_id) { |data| }
273
+ }.to raise_error(ArgumentError, 'Path must start with a slash')
274
+ end
275
+ end
219
276
  end
@@ -25,14 +25,6 @@ describe Puppet::HTTP::Service::Report do
25
25
 
26
26
  subject.put_report('report', report, environment: environment)
27
27
  end
28
-
29
- it 'includes the X-Puppet-Profiling header when Puppet[:profile] is true' do
30
- stub_request(:put, uri).with(headers: {'X-Puppet-Version' => /./, 'User-Agent' => /./, 'X-Puppet-Profiling' => 'true'})
31
-
32
- Puppet[:profile] = true
33
-
34
- subject.put_report('report', report, environment: environment)
35
- end
36
28
  end
37
29
 
38
30
  context 'when routing to the report service' do
@@ -60,6 +52,15 @@ describe Puppet::HTTP::Service::Report do
60
52
  context 'when submitting a report' do
61
53
  let(:url) { "https://www.example.com/puppet/v3/report/infinity?environment=testing" }
62
54
 
55
+ it 'includes puppet headers set via the :http_extra_headers and :profile settings' do
56
+ stub_request(:put, url).with(headers: {'Example-Header' => 'real-thing', 'another' => 'thing', 'X-Puppet-Profiling' => 'true'})
57
+
58
+ Puppet[:http_extra_headers] = 'Example-Header:real-thing,another:thing'
59
+ Puppet[:profile] = true
60
+
61
+ subject.put_report('infinity', report, environment: environment)
62
+ end
63
+
63
64
  it 'submits a report to the "report" endpoint' do
64
65
  stub_request(:put, url)
65
66
  .with(
@@ -79,6 +80,14 @@ describe Puppet::HTTP::Service::Report do
79
80
  subject.put_report('node name', report, environment: environment)
80
81
  end
81
82
 
83
+ it 'returns the response whose body contains the list of report processors' do
84
+ body = "[\"store\":\"http\"]"
85
+ stub_request(:put, url)
86
+ .to_return(status: 200, body: body, headers: {'Content-Type' => 'application/json'})
87
+
88
+ expect(subject.put_report('infinity', report, environment: environment).body).to eq(body)
89
+ end
90
+
82
91
  it 'raises response error if unsuccessful' do
83
92
  stub_request(:put, url).to_return(status: [400, 'Bad Request'], headers: {'X-Puppet-Version' => '6.1.8' })
84
93
 
@@ -1,19 +1,79 @@
1
1
  require 'spec_helper'
2
2
  require 'webmock/rspec'
3
3
  require 'puppet/http'
4
+ require 'puppet/file_serving'
5
+ require 'puppet/file_serving/content'
6
+ require 'puppet/file_serving/metadata'
4
7
 
5
8
  describe Puppet::HTTP::Service do
6
9
  let(:ssl_context) { Puppet::SSL::SSLContext.new }
7
10
  let(:client) { Puppet::HTTP::Client.new(ssl_context: ssl_context) }
11
+ let(:session) { Puppet::HTTP::Session.new(client, []) }
8
12
  let(:url) { URI.parse('https://www.example.com') }
9
- let(:service) { described_class.new(client, url) }
13
+ let(:service) { described_class.new(client, session, url) }
14
+
15
+ class TestService < Puppet::HTTP::Service
16
+ def get_test(ssl_context)
17
+ @client.get(
18
+ url,
19
+ headers: add_puppet_headers({'Default-Header' => 'default-value'}),
20
+ ssl_context: ssl_context
21
+ )
22
+ end
23
+
24
+ def mime_types(model)
25
+ get_mime_types(model)
26
+ end
27
+ end
28
+
29
+ context 'when modifying headers for an http request' do
30
+ let(:service) { TestService.new(client, session, url) }
31
+
32
+ it 'adds custom user-specified headers' do
33
+ stub_request(:get, "https://www.example.com/").
34
+ with( headers: { 'Default-Header'=>'default-value', 'Header2'=>'newvalue' })
35
+
36
+ Puppet[:http_extra_headers] = 'header2:newvalue'
37
+
38
+ service.get_test(ssl_context)
39
+ end
40
+
41
+ it 'adds X-Puppet-Profiling header if set' do
42
+ stub_request(:get, "https://www.example.com/").
43
+ with( headers: { 'Default-Header'=>'default-value', 'X-Puppet-Profiling'=>'true' })
44
+
45
+ Puppet[:profile] = true
46
+
47
+ service.get_test(ssl_context)
48
+ end
49
+
50
+ it 'ignores a custom header does not have a value' do
51
+ stub_request(:get, "https://www.example.com/").with do |request|
52
+ expect(request.headers).to include({'Default-Header' => 'default-value'})
53
+ expect(request.headers).to_not include('header-with-no-value')
54
+ end
55
+
56
+ Puppet[:http_extra_headers] = 'header-with-no-value:'
57
+
58
+ service.get_test(ssl_context)
59
+ end
60
+
61
+ it 'ignores a custom header that already exists (case insensitive) in the header hash' do
62
+ stub_request(:get, "https://www.example.com/").
63
+ with( headers: { 'Default-Header'=>'default-value' })
64
+
65
+ Puppet[:http_extra_headers] = 'default-header:wrongvalue'
66
+
67
+ service.get_test(ssl_context)
68
+ end
69
+ end
10
70
 
11
71
  it "returns a URI containing the base URL and path" do
12
72
  expect(service.with_base_url('/puppet/v3')).to eq(URI.parse("https://www.example.com/puppet/v3"))
13
73
  end
14
74
 
15
75
  it "doesn't modify frozen the base URL" do
16
- service = described_class.new(client, url.freeze)
76
+ service = described_class.new(client, session, url.freeze)
17
77
  service.with_base_url('/puppet/v3')
18
78
  end
19
79
 
@@ -36,7 +96,7 @@ describe Puppet::HTTP::Service do
36
96
 
37
97
  it 'raises for unknown service names' do
38
98
  expect {
39
- described_class.create_service(client, :westbound)
99
+ described_class.create_service(client, session, :westbound)
40
100
  }.to raise_error(ArgumentError, "Unknown service westbound")
41
101
  end
42
102
 
@@ -53,4 +113,33 @@ describe Puppet::HTTP::Service do
53
113
  it "returns false for unknown service names" do
54
114
  expect(described_class.valid_name?(:westbound)).to eq(false)
55
115
  end
116
+
117
+ it 'returns different mime types for different models' do
118
+ mimes = if Puppet.features.msgpack?
119
+ %w[application/json application/x-msgpack text/pson]
120
+ else
121
+ %w[application/json text/pson]
122
+ end
123
+
124
+ service = TestService.new(client, session, url)
125
+ [
126
+ Puppet::Node,
127
+ Puppet::Node::Facts,
128
+ Puppet::Transaction::Report,
129
+ Puppet::FileServing::Metadata,
130
+ Puppet::Status
131
+ ].each do |model|
132
+ expect(service.mime_types(model)).to eq(mimes)
133
+ end
134
+
135
+ # These are special
136
+ expect(service.mime_types(Puppet::FileServing::Content)).to eq(%w[application/octet-stream])
137
+
138
+ catalog_mimes = if Puppet.features.msgpack?
139
+ %w[application/vnd.puppet.rich+json application/json application/vnd.puppet.rich+msgpack application/x-msgpack text/pson]
140
+ else
141
+ %w[application/vnd.puppet.rich+json application/json application/vnd.puppet.rich+msgpack text/pson]
142
+ end
143
+ expect(service.mime_types(Puppet::Resource::Catalog)).to eq(catalog_mimes)
144
+ end
56
145
  end
@@ -155,7 +155,6 @@ describe Puppet::HTTP::Session do
155
155
  }.to raise_error(Puppet::Error, "Could not select a functional puppet master from server_list: 'foo.example.com,bar.example.com'")
156
156
  end
157
157
 
158
-
159
158
  it "raises when there are no more routes" do
160
159
  allow_any_instance_of(Net::HTTP).to receive(:start).and_raise(Errno::EHOSTUNREACH)
161
160
  session = client.create_session
@@ -164,5 +163,109 @@ describe Puppet::HTTP::Session do
164
163
  session.route_to(:ca)
165
164
  }.to raise_error(Puppet::HTTP::RouteError, 'No more routes to ca')
166
165
  end
166
+
167
+ Puppet::HTTP::Service::SERVICE_NAMES.each do |name|
168
+ it "resolves #{name} using server_list" do
169
+ stub_request(:get, "https://ca.example.com:8141/status/v1/simple/master").to_return(status: 200)
170
+
171
+ session.route_to(name)
172
+ end
173
+ end
174
+
175
+ it 'does not use server_list to resolve the ca service when ca_server is explicitly set' do
176
+ Puppet[:ca_server] = 'banana.example.com'
177
+
178
+ expect(session.route_to(:ca).url.to_s).to eq("https://banana.example.com:8140/puppet-ca/v1")
179
+ end
180
+
181
+ it 'does not use server_list to resolve the report service when the report_server is explicitly set' do
182
+ Puppet[:report_server] = 'cherry.example.com'
183
+
184
+ expect(session.route_to(:report).url.to_s).to eq("https://cherry.example.com:8140/puppet/v3")
185
+ end
186
+ end
187
+
188
+ context 'when retrieving capabilities' do
189
+ let(:session) do
190
+ resolver = DummyResolver.new(good_service)
191
+ described_class.new(client, [resolver])
192
+ end
193
+
194
+ it 'raises for unknown service names' do
195
+ expect {
196
+ session = described_class.new(client, [])
197
+ session.supports?(:westbound, 'a capability')
198
+ }.to raise_error(ArgumentError, "Unknown service westbound")
199
+ end
200
+
201
+ context 'locales' do
202
+ it 'does not support locales if the cached service has not been resolved' do
203
+ session = described_class.new(client, [])
204
+
205
+ expect(session).to_not be_supports(:puppet, 'locales')
206
+ end
207
+
208
+ it "supports locales if the cached service's version is 5.3.4 or greater" do
209
+ response = Puppet::HTTP::Response.new({'X-Puppet-Version' => '5.3.4'}, uri)
210
+
211
+ session.route_to(:puppet)
212
+ session.process_response(response)
213
+
214
+ expect(session).to be_supports(:puppet, 'locales')
215
+ end
216
+
217
+ it "does not support locales if the cached service's version is 5.3.3" do
218
+ response = Puppet::HTTP::Response.new({'X-Puppet-Version' => '5.3.3'}, uri)
219
+
220
+ session.route_to(:puppet)
221
+ session.process_response(response)
222
+
223
+ expect(session).to_not be_supports(:puppet, 'locales')
224
+ end
225
+
226
+ it "does not support locales if the cached service's version is missing" do
227
+ response = Puppet::HTTP::Response.new({}, uri)
228
+
229
+ session.route_to(:puppet)
230
+ session.process_response(response)
231
+
232
+ expect(session).to_not be_supports(:puppet, 'locales')
233
+ end
234
+ end
235
+
236
+ context 'json' do
237
+ it 'does not support json if the cached service has not been resolved' do
238
+ session = described_class.new(client, [])
239
+
240
+ expect(session).to_not be_supports(:puppet, 'json')
241
+ end
242
+
243
+ it "supports json if the cached service's version is 5 or greater" do
244
+ response = Puppet::HTTP::Response.new({'X-Puppet-Version' => '5.5.12'}, uri)
245
+
246
+ session.route_to(:puppet)
247
+ session.process_response(response)
248
+
249
+ expect(session).to be_supports(:puppet, 'json')
250
+ end
251
+
252
+ it "does not support json if the cached service's version is less than 5.0" do
253
+ response = Puppet::HTTP::Response.new({'X-Puppet-Version' => '4.10.1'}, uri)
254
+
255
+ session.route_to(:puppet)
256
+ session.process_response(response)
257
+
258
+ expect(session).to_not be_supports(:puppet, 'json')
259
+ end
260
+
261
+ it "supports json if the cached service's version is missing" do
262
+ response = Puppet::HTTP::Response.new({}, uri)
263
+
264
+ session.route_to(:puppet)
265
+ session.process_response(response)
266
+
267
+ expect(session).to be_supports(:puppet, 'json')
268
+ end
269
+ end
167
270
  end
168
271
  end
@@ -3,7 +3,64 @@ require 'spec_helper'
3
3
  require 'puppet/indirector/catalog/rest'
4
4
 
5
5
  describe Puppet::Resource::Catalog::Rest do
6
- it "should be a sublcass of Puppet::Indirector::REST" do
7
- expect(Puppet::Resource::Catalog::Rest.superclass).to equal(Puppet::Indirector::REST)
6
+ let(:certname) { 'ziggy' }
7
+ let(:uri) { %r{/puppet/v3/catalog/ziggy} }
8
+ let(:formatter) { Puppet::Network::FormatHandler.format(:json) }
9
+ let(:catalog) { Puppet::Resource::Catalog.new(certname) }
10
+
11
+ before :each do
12
+ Puppet[:server] = 'compiler.example.com'
13
+ Puppet[:masterport] = 8140
14
+
15
+ described_class.indirection.terminus_class = :rest
16
+ end
17
+
18
+ def catalog_response(catalog)
19
+ { body: formatter.render(catalog), headers: {'Content-Type' => formatter.mime } }
20
+ end
21
+
22
+ it 'finds a catalog' do
23
+ stub_request(:post, uri).to_return(**catalog_response(catalog))
24
+
25
+ expect(described_class.indirection.find(certname)).to be_a(Puppet::Resource::Catalog)
26
+ end
27
+
28
+ it "serializes the environment" do
29
+ stub_request(:post, uri)
30
+ .with(query: hash_including('environment' => 'outerspace'))
31
+ .to_return(**catalog_response(catalog))
32
+
33
+ described_class.indirection.find(certname, environment: Puppet::Node::Environment.remote('outerspace'))
34
+ end
35
+
36
+ it 'constructs a catalog environment_instance' do
37
+ env = Puppet::Node::Environment.remote('outerspace')
38
+ catalog = Puppet::Resource::Catalog.new(certname, env)
39
+
40
+ stub_request(:post, uri).to_return(**catalog_response(catalog))
41
+
42
+ expect(described_class.indirection.find(certname).environment_instance).to eq(env)
43
+ end
44
+
45
+ it 'returns nil if the node does not exist' do
46
+ stub_request(:post, uri).to_return(status: 404, headers: { 'Content-Type' => 'application/json' }, body: "{}")
47
+
48
+ expect(described_class.indirection.find(certname)).to be_nil
49
+ end
50
+
51
+ it 'raises if fail_on_404 is specified' do
52
+ stub_request(:post, uri).to_return(status: 404, headers: { 'Content-Type' => 'application/json' }, body: "{}")
53
+
54
+ expect{
55
+ described_class.indirection.find(certname, fail_on_404: true)
56
+ }.to raise_error(Puppet::Error, %r{Find /puppet/v3/catalog/ziggy resulted in 404 with the message: {}})
57
+ end
58
+
59
+ it 'raises Net::HTTPError on 500' do
60
+ stub_request(:post, uri).to_return(status: 500)
61
+
62
+ expect{
63
+ described_class.indirection.find(certname)
64
+ }.to raise_error(Net::HTTPError, %r{Error 500 on SERVER: })
8
65
  end
9
66
  end