puppet 6.10.1 → 6.11.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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -4
  3. data/Gemfile.lock +20 -12
  4. data/ext/project_data.yaml +3 -2
  5. data/ext/regexp_nodes/regexp_nodes.rb +4 -4
  6. data/ext/windows/service/daemon.rb +33 -8
  7. data/install.rb +6 -6
  8. data/lib/puppet.rb +8 -0
  9. data/lib/puppet/application.rb +1 -1
  10. data/lib/puppet/application/agent.rb +3 -0
  11. data/lib/puppet/application/apply.rb +2 -2
  12. data/lib/puppet/application/describe.rb +3 -9
  13. data/lib/puppet/application/device.rb +3 -0
  14. data/lib/puppet/application/doc.rb +1 -1
  15. data/lib/puppet/application/lookup.rb +1 -1
  16. data/lib/puppet/application/script.rb +2 -2
  17. data/lib/puppet/application/ssl.rb +25 -21
  18. data/lib/puppet/configurer.rb +42 -0
  19. data/lib/puppet/configurer/downloader.rb +2 -6
  20. data/lib/puppet/context/trusted_information.rb +42 -4
  21. data/lib/puppet/defaults.rb +19 -4
  22. data/lib/puppet/face/module/list.rb +5 -5
  23. data/lib/puppet/face/module/search.rb +1 -1
  24. data/lib/puppet/face/module/uninstall.rb +1 -1
  25. data/lib/puppet/face/module/upgrade.rb +1 -1
  26. data/lib/puppet/file_serving/http_metadata.rb +1 -1
  27. data/lib/puppet/file_system.rb +0 -8
  28. data/lib/puppet/file_system/memory_file.rb +1 -1
  29. data/lib/puppet/file_system/posix.rb +3 -2
  30. data/lib/puppet/forge.rb +3 -3
  31. data/lib/puppet/functions.rb +1 -2
  32. data/lib/puppet/gettext/module_translations.rb +1 -1
  33. data/lib/puppet/graph/rb_tree_map.rb +2 -2
  34. data/lib/puppet/graph/simple_graph.rb +4 -3
  35. data/lib/puppet/http.rb +29 -0
  36. data/lib/puppet/http/client.rb +156 -0
  37. data/lib/puppet/http/errors.rb +30 -0
  38. data/lib/puppet/http/redirector.rb +48 -0
  39. data/lib/puppet/http/resolver.rb +5 -0
  40. data/lib/puppet/http/resolver/settings.rb +5 -0
  41. data/lib/puppet/http/resolver/srv.rb +13 -0
  42. data/lib/puppet/http/response.rb +34 -0
  43. data/lib/puppet/http/retry_after_handler.rb +47 -0
  44. data/lib/puppet/http/service.rb +18 -0
  45. data/lib/puppet/http/service/ca.rb +49 -0
  46. data/lib/puppet/http/session.rb +55 -0
  47. data/lib/puppet/indirector/file_bucket_file/file.rb +1 -1
  48. data/lib/puppet/indirector/hiera.rb +2 -0
  49. data/lib/puppet/indirector/request.rb +1 -1
  50. data/lib/puppet/indirector/resource/ral.rb +1 -3
  51. data/lib/puppet/indirector/resource/validator.rb +1 -1
  52. data/lib/puppet/interface.rb +2 -1
  53. data/lib/puppet/interface/documentation.rb +1 -1
  54. data/lib/puppet/loaders.rb +0 -1
  55. data/lib/puppet/metatype/manager.rb +1 -1
  56. data/lib/puppet/module.rb +1 -1
  57. data/lib/puppet/module/task.rb +20 -4
  58. data/lib/puppet/module_tool/applications/installer.rb +1 -1
  59. data/lib/puppet/module_tool/applications/uninstaller.rb +3 -3
  60. data/lib/puppet/module_tool/metadata.rb +1 -1
  61. data/lib/puppet/module_tool/shared_behaviors.rb +4 -4
  62. data/lib/puppet/module_tool/tar/mini.rb +1 -1
  63. data/lib/puppet/network/http.rb +2 -6
  64. data/lib/puppet/network/http/api/indirected_routes.rb +12 -11
  65. data/lib/puppet/network/http/connection.rb +10 -12
  66. data/lib/puppet/network/http/pool.rb +2 -0
  67. data/lib/puppet/network/http/site.rb +5 -1
  68. data/lib/puppet/network/resolver.rb +4 -4
  69. data/lib/puppet/node/environment.rb +4 -2
  70. data/lib/puppet/pal/pal_impl.rb +2 -2
  71. data/lib/puppet/parser/ast.rb +1 -1
  72. data/lib/puppet/parser/ast/resourceparam.rb +1 -1
  73. data/lib/puppet/parser/functions.rb +1 -1
  74. data/lib/puppet/parser/scope.rb +8 -7
  75. data/lib/puppet/pops/evaluator/collectors/catalog_collector.rb +1 -1
  76. data/lib/puppet/pops/evaluator/collectors/exported_collector.rb +1 -1
  77. data/lib/puppet/pops/evaluator/external_syntax_support.rb +3 -2
  78. data/lib/puppet/pops/evaluator/runtime3_support.rb +4 -7
  79. data/lib/puppet/pops/loader/module_loaders.rb +1 -1
  80. data/lib/puppet/pops/loader/task_instantiator.rb +4 -0
  81. data/lib/puppet/pops/loaders.rb +1 -1
  82. data/lib/puppet/pops/lookup/hiera_config.rb +1 -0
  83. data/lib/puppet/pops/lookup/sub_lookup.rb +1 -1
  84. data/lib/puppet/pops/merge_strategy.rb +22 -18
  85. data/lib/puppet/pops/parser/heredoc_support.rb +1 -1
  86. data/lib/puppet/pops/parser/interpolation_support.rb +4 -4
  87. data/lib/puppet/pops/parser/locator.rb +1 -1
  88. data/lib/puppet/pops/parser/pn_parser.rb +17 -16
  89. data/lib/puppet/pops/puppet_stack.rb +52 -48
  90. data/lib/puppet/pops/types/p_sensitive_type.rb +1 -1
  91. data/lib/puppet/pops/types/p_uri_type.rb +1 -1
  92. data/lib/puppet/pops/types/string_converter.rb +10 -10
  93. data/lib/puppet/pops/types/types.rb +3 -3
  94. data/lib/puppet/property.rb +1 -1
  95. data/lib/puppet/property/ensure.rb +1 -1
  96. data/lib/puppet/provider/exec.rb +6 -2
  97. data/lib/puppet/provider/nameservice/directoryservice.rb +1 -1
  98. data/lib/puppet/provider/nameservice/pw.rb +2 -2
  99. data/lib/puppet/provider/package/apt.rb +5 -1
  100. data/lib/puppet/provider/package/dnfmodule.rb +87 -0
  101. data/lib/puppet/provider/package/dpkg.rb +31 -17
  102. data/lib/puppet/provider/package/openbsd.rb +1 -1
  103. data/lib/puppet/provider/package/pip.rb +34 -9
  104. data/lib/puppet/provider/package/portage.rb +1 -1
  105. data/lib/puppet/provider/package/rpm.rb +5 -5
  106. data/lib/puppet/provider/package/windows/package.rb +1 -1
  107. data/lib/puppet/provider/package/yum.rb +1 -1
  108. data/lib/puppet/provider/parsedfile.rb +1 -1
  109. data/lib/puppet/provider/service/daemontools.rb +9 -9
  110. data/lib/puppet/provider/service/openbsd.rb +1 -1
  111. data/lib/puppet/provider/service/rcng.rb +2 -2
  112. data/lib/puppet/provider/service/runit.rb +2 -8
  113. data/lib/puppet/provider/service/systemd.rb +10 -10
  114. data/lib/puppet/provider/user/directoryservice.rb +1 -1
  115. data/lib/puppet/provider/user/user_role_add.rb +1 -1
  116. data/lib/puppet/provider/user/useradd.rb +22 -13
  117. data/lib/puppet/provider/user/windows_adsi.rb +4 -5
  118. data/lib/puppet/reference/indirection.rb +2 -2
  119. data/lib/puppet/reference/metaparameter.rb +1 -3
  120. data/lib/puppet/reference/providers.rb +1 -1
  121. data/lib/puppet/reference/type.rb +3 -9
  122. data/lib/puppet/reports.rb +1 -1
  123. data/lib/puppet/resource.rb +1 -1
  124. data/lib/puppet/resource/catalog.rb +1 -1
  125. data/lib/puppet/rest/errors.rb +1 -0
  126. data/lib/puppet/rest/response.rb +1 -0
  127. data/lib/puppet/rest/route.rb +1 -0
  128. data/lib/puppet/rest/routes.rb +3 -0
  129. data/lib/puppet/runtime.rb +25 -0
  130. data/lib/puppet/settings.rb +3 -3
  131. data/lib/puppet/settings/environment_conf.rb +1 -0
  132. data/lib/puppet/ssl/host.rb +1 -1
  133. data/lib/puppet/ssl/oids.rb +1 -1
  134. data/lib/puppet/ssl/state_machine.rb +23 -15
  135. data/lib/puppet/test/test_helper.rb +1 -1
  136. data/lib/puppet/transaction/report.rb +1 -1
  137. data/lib/puppet/trusted_external.rb +13 -0
  138. data/lib/puppet/type.rb +1 -3
  139. data/lib/puppet/type/exec.rb +7 -3
  140. data/lib/puppet/type/file.rb +1 -2
  141. data/lib/puppet/type/file/source.rb +2 -2
  142. data/lib/puppet/type/package.rb +10 -3
  143. data/lib/puppet/type/schedule.rb +1 -1
  144. data/lib/puppet/type/service.rb +1 -1
  145. data/lib/puppet/util.rb +2 -2
  146. data/lib/puppet/util/command_line/trollop.rb +1 -1
  147. data/lib/puppet/util/http_proxy.rb +2 -10
  148. data/lib/puppet/util/log.rb +2 -2
  149. data/lib/puppet/util/log/destinations.rb +2 -2
  150. data/lib/puppet/util/logging.rb +2 -2
  151. data/lib/puppet/util/metric.rb +2 -2
  152. data/lib/puppet/util/platform.rb +15 -4
  153. data/lib/puppet/util/provider_features.rb +2 -4
  154. data/lib/puppet/util/rdoc.rb +1 -1
  155. data/lib/puppet/util/reference.rb +1 -1
  156. data/lib/puppet/util/resource_template.rb +1 -1
  157. data/lib/puppet/util/selinux.rb +3 -1
  158. data/lib/puppet/util/windows/registry.rb +7 -5
  159. data/lib/puppet/vendor.rb +1 -1
  160. data/lib/puppet/vendor/require_vendored.rb +0 -1
  161. data/lib/puppet/version.rb +1 -1
  162. data/lib/puppet/x509/cert_provider.rb +4 -1
  163. data/locales/puppet.pot +279 -203
  164. data/man/man5/puppet.conf.5 +30 -8
  165. data/man/man8/puppet-agent.8 +4 -1
  166. data/man/man8/puppet-apply.8 +1 -1
  167. data/man/man8/puppet-catalog.8 +1 -1
  168. data/man/man8/puppet-config.8 +1 -1
  169. data/man/man8/puppet-describe.8 +1 -1
  170. data/man/man8/puppet-device.8 +1 -1
  171. data/man/man8/puppet-doc.8 +1 -1
  172. data/man/man8/puppet-epp.8 +1 -1
  173. data/man/man8/puppet-facts.8 +1 -1
  174. data/man/man8/puppet-filebucket.8 +1 -1
  175. data/man/man8/puppet-generate.8 +1 -1
  176. data/man/man8/puppet-help.8 +1 -1
  177. data/man/man8/puppet-key.8 +1 -1
  178. data/man/man8/puppet-lookup.8 +1 -1
  179. data/man/man8/puppet-man.8 +1 -1
  180. data/man/man8/puppet-module.8 +1 -1
  181. data/man/man8/puppet-node.8 +1 -1
  182. data/man/man8/puppet-parser.8 +1 -1
  183. data/man/man8/puppet-plugin.8 +1 -1
  184. data/man/man8/puppet-report.8 +1 -1
  185. data/man/man8/puppet-resource.8 +1 -1
  186. data/man/man8/puppet-script.8 +1 -1
  187. data/man/man8/puppet-ssl.8 +1 -1
  188. data/man/man8/puppet-status.8 +1 -1
  189. data/man/man8/puppet.8 +2 -2
  190. data/spec/fixtures/unit/provider/package/dnfmodule/dnf-module-list-installed.txt +11 -0
  191. data/spec/integration/configurer_spec.rb +52 -0
  192. data/spec/lib/puppet/certificate_factory.rb +2 -2
  193. data/spec/spec_helper.rb +24 -0
  194. data/spec/unit/application/device_spec.rb +6 -0
  195. data/spec/unit/application/ssl_spec.rb +4 -7
  196. data/spec/unit/configurer_spec.rb +1 -0
  197. data/spec/unit/context/trusted_information_spec.rb +41 -2
  198. data/spec/unit/http/client_spec.rb +440 -0
  199. data/spec/unit/http/resolver_spec.rb +45 -0
  200. data/spec/unit/http/service/ca_spec.rb +106 -0
  201. data/spec/unit/http/service_spec.rb +32 -0
  202. data/spec/unit/http/session_spec.rb +102 -0
  203. data/spec/unit/indirector/resource/ral_spec.rb +4 -4
  204. data/spec/unit/network/http/connection_spec.rb +119 -145
  205. data/spec/unit/network/http/site_spec.rb +7 -0
  206. data/spec/unit/parser/scope_spec.rb +10 -0
  207. data/spec/unit/pops/loaders/loaders_spec.rb +13 -2
  208. data/spec/unit/pops/loaders/module_loaders_spec.rb +37 -0
  209. data/spec/unit/provider/exec_spec.rb +209 -0
  210. data/spec/unit/provider/package/dnfmodule_spec.rb +186 -0
  211. data/spec/unit/provider/package/dpkg_spec.rb +238 -78
  212. data/spec/unit/provider/package/pip_spec.rb +51 -6
  213. data/spec/unit/provider/service/daemontools_spec.rb +24 -0
  214. data/spec/unit/provider/service/runit_spec.rb +24 -0
  215. data/spec/unit/provider/service/systemd_spec.rb +25 -25
  216. data/spec/unit/provider/user/useradd_spec.rb +46 -0
  217. data/spec/unit/ssl/host_spec.rb +0 -5
  218. data/spec/unit/ssl/state_machine_spec.rb +16 -10
  219. data/spec/unit/type/exec_spec.rb +6 -12
  220. data/spec/unit/type/file_spec.rb +9 -4
  221. data/spec/unit/type/package_spec.rb +5 -0
  222. data/spec/unit/util/execution_spec.rb +16 -0
  223. data/spec/unit/util/http_proxy_spec.rb +79 -27
  224. data/spec/unit/util/log/destinations_spec.rb +7 -3
  225. metadata +45 -22
  226. data/lib/puppet/pops/loader/null_loader.rb +0 -60
  227. data/lib/puppet/vendor/deep_merge/CHANGELOG +0 -45
  228. data/lib/puppet/vendor/deep_merge/Gemfile +0 -3
  229. data/lib/puppet/vendor/deep_merge/LICENSE +0 -21
  230. data/lib/puppet/vendor/deep_merge/PUPPET_README.md +0 -6
  231. data/lib/puppet/vendor/deep_merge/README.md +0 -113
  232. data/lib/puppet/vendor/deep_merge/Rakefile +0 -19
  233. data/lib/puppet/vendor/deep_merge/deep_merge.gemspec +0 -35
  234. data/lib/puppet/vendor/deep_merge/lib/deep_merge.rb +0 -2
  235. data/lib/puppet/vendor/deep_merge/lib/deep_merge/core.rb +0 -210
  236. data/lib/puppet/vendor/deep_merge/lib/deep_merge/deep_merge_hash.rb +0 -28
  237. data/lib/puppet/vendor/deep_merge/lib/deep_merge/rails_compat.rb +0 -27
  238. data/lib/puppet/vendor/deep_merge/test/test_deep_merge.rb +0 -608
  239. data/lib/puppet/vendor/load_deep_merge.rb +0 -1
  240. data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_get/should_yield_to_the_block.yml +0 -24
  241. data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_head/should_yield_to_the_block.yml +0 -24
  242. data/spec/fixtures/vcr/cassettes/Puppet_Network_HTTP_Connection/when_handling_requests/_request_post/should_yield_to_the_block.yml +0 -24
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ require 'webmock/rspec'
3
+ require 'puppet/http'
4
+
5
+ describe Puppet::HTTP::Resolver do
6
+ let(:ssl_context) { Puppet::SSL::SSLContext.new }
7
+ let(:client) { Puppet::HTTP::Client.new(ssl_context: ssl_context) }
8
+ let(:session) { client.create_session }
9
+ let(:uri) { URI.parse('https://www.example.com') }
10
+
11
+ context 'when resolving using settings' do
12
+ let(:subject) { Puppet::HTTP::Resolver::Settings.new }
13
+
14
+ it 'yields a service based on the current ca_server and ca_port settings' do
15
+ Puppet[:ca_server] = 'ca.example.com'
16
+ Puppet[:ca_port] = 8141
17
+
18
+ subject.resolve(session, :ca) do |service|
19
+ expect(service).to be_an_instance_of(Puppet::HTTP::Service::Ca)
20
+ expect(service.url.to_s).to eq("https://ca.example.com:8141/puppet-ca/v1")
21
+ end
22
+ end
23
+ end
24
+
25
+ context 'when resolving using SRV' do
26
+ let(:dns) { double('dns') }
27
+ let(:subject) { Puppet::HTTP::Resolver::SRV.new(domain: 'example.com', dns: dns) }
28
+
29
+ def stub_srv(host, port)
30
+ srv = Resolv::DNS::Resource::IN::SRV.new(0, 0, port, host)
31
+ srv.instance_variable_set :@ttl, 3600
32
+
33
+ allow(dns).to receive(:getresources).with("_x-puppet-ca._tcp.example.com", Resolv::DNS::Resource::IN::SRV).and_return([srv])
34
+ end
35
+
36
+ it 'yields a service based on an SRV record' do
37
+ stub_srv('ca1.example.com', 8142)
38
+
39
+ subject.resolve(session, :ca) do |service|
40
+ expect(service).to be_an_instance_of(Puppet::HTTP::Service::Ca)
41
+ expect(service.url.to_s).to eq("https://ca1.example.com:8142/puppet-ca/v1")
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+ require 'webmock/rspec'
3
+ require 'puppet/http'
4
+
5
+ describe Puppet::HTTP::Service::Ca do
6
+ let(:ssl_context) { Puppet::SSL::SSLContext.new }
7
+ let(:client) { Puppet::HTTP::Client.new(ssl_context: ssl_context) }
8
+ let(:base_url) { URI.parse('https://www.example.com') }
9
+ let(:subject) { described_class.new(client, base_url) }
10
+
11
+ context 'when getting certificates' do
12
+ let(:cert) { cert_fixture('ca.pem') }
13
+ let(:pem) { cert.to_pem }
14
+ let(:url) { "https://www.example.com/certificate/ca" }
15
+
16
+ it 'gets a certificate from the "certificate" endpoint' do
17
+ stub_request(:get, url).to_return(body: pem)
18
+
19
+ expect(subject.get_certificate('ca')).to eq(pem)
20
+ end
21
+
22
+ it 'accepts text/plain responses' do
23
+ stub_request(:get, url).with(headers: {'Accept' => 'text/plain'})
24
+
25
+ subject.get_certificate('ca')
26
+ end
27
+
28
+ it 'raises a response error if unsuccessful' do
29
+ stub_request(:get, url).to_return(status: [404, 'Not Found'])
30
+
31
+ expect {
32
+ subject.get_certificate('ca')
33
+ }.to raise_error do |err|
34
+ expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
35
+ expect(err.message).to eq("Not Found")
36
+ expect(err.response.code).to eq(404)
37
+ end
38
+ end
39
+ end
40
+
41
+ context 'when getting CRLs' do
42
+ let(:crl) { crl_fixture('crl.pem') }
43
+ let(:pem) { crl.to_pem }
44
+ let(:url) { "https://www.example.com/certificate_revocation_list/ca" }
45
+
46
+ it 'gets a CRL from "certificate_revocation_list" endpoint' do
47
+ stub_request(:get, url).to_return(body: pem)
48
+
49
+ expect(subject.get_certificate_revocation_list).to eq(pem)
50
+ end
51
+
52
+ it 'accepts text/plain responses' do
53
+ stub_request(:get, url).with(headers: {'Accept' => 'text/plain'})
54
+
55
+ subject.get_certificate_revocation_list
56
+ end
57
+
58
+ it 'raises a response error if unsuccessful' do
59
+ stub_request(:get, url).to_return(status: [404, 'Not Found'])
60
+
61
+ expect {
62
+ subject.get_certificate_revocation_list
63
+ }.to raise_error do |err|
64
+ expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
65
+ expect(err.message).to eq("Not Found")
66
+ expect(err.response.code).to eq(404)
67
+ end
68
+ end
69
+
70
+ it 'raises a 304 response error if it is unmodified' do
71
+ stub_request(:get, url).to_return(status: [304, 'Not Modified'])
72
+
73
+ expect {
74
+ subject.get_certificate_revocation_list(if_modified_since: Time.now)
75
+ }.to raise_error do |err|
76
+ expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
77
+ expect(err.message).to eq("Not Modified")
78
+ expect(err.response.code).to eq(304)
79
+ end
80
+ end
81
+ end
82
+
83
+ context 'when submitting a CSR' do
84
+ let(:request) { request_fixture('request.pem') }
85
+ let(:pem) { request.to_pem }
86
+ let(:url) { "https://www.example.com/certificate_request/infinity" }
87
+
88
+ it 'submits a CSR to the "certificate_request" endpoint' do
89
+ stub_request(:put, url).with(body: pem, headers: { 'Content-Type' => 'text/plain' })
90
+
91
+ subject.put_certificate_request('infinity', request)
92
+ end
93
+
94
+ it 'raises response error if unsuccessful' do
95
+ stub_request(:put, url).to_return(status: [400, 'Bad Request'])
96
+
97
+ expect {
98
+ subject.put_certificate_request('infinity', request)
99
+ }.to raise_error do |err|
100
+ expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
101
+ expect(err.message).to eq('Bad Request')
102
+ expect(err.response.code).to eq(400)
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ require 'webmock/rspec'
3
+ require 'puppet/http'
4
+
5
+ describe Puppet::HTTP::Service do
6
+ let(:ssl_context) { Puppet::SSL::SSLContext.new }
7
+ let(:client) { Puppet::HTTP::Client.new(ssl_context: ssl_context) }
8
+ let(:url) { URI.parse('https://www.example.com') }
9
+ let(:service) { described_class.new(client, url) }
10
+
11
+ it "returns a URI containing the base URL and path" do
12
+ expect(service.with_base_url('/puppet/v3')).to eq(URI.parse("https://www.example.com/puppet/v3"))
13
+ end
14
+
15
+ it "doesn't modify frozen the base URL" do
16
+ service = described_class.new(client, url.freeze)
17
+ service.with_base_url('/puppet/v3')
18
+ end
19
+
20
+ it "connects to the base URL with a nil ssl context" do
21
+ expect(client).to receive(:connect).with(url, ssl_context: nil)
22
+
23
+ service.connect
24
+ end
25
+
26
+ it "accepts an optional ssl_context" do
27
+ other_ctx = Puppet::SSL::SSLContext.new
28
+ expect(client).to receive(:connect).with(url, ssl_context: other_ctx)
29
+
30
+ service.connect(ssl_context: other_ctx)
31
+ end
32
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+ require 'webmock/rspec'
3
+ require 'puppet/http'
4
+
5
+ describe Puppet::HTTP::Session do
6
+ let(:ssl_context) { Puppet::SSL::SSLContext.new }
7
+ let(:client) { Puppet::HTTP::Client.new(ssl_context: ssl_context) }
8
+ let(:uri) { URI.parse('https://www.example.com') }
9
+ let(:good_service) {
10
+ double('good', url: uri, connect: nil)
11
+ }
12
+ let(:bad_service) {
13
+ service = double('good', url: uri)
14
+ allow(service).to receive(:connect).and_raise(Puppet::HTTP::ConnectionError, 'whoops')
15
+ service
16
+ }
17
+
18
+ class DummyResolver
19
+ attr_reader :count
20
+
21
+ def initialize(service)
22
+ @service = service
23
+ @count = 0
24
+ end
25
+
26
+ def resolve(session, name, &block)
27
+ @count += 1
28
+ yield @service
29
+ end
30
+ end
31
+
32
+ context 'when routing' do
33
+ it 'returns the first resolved service' do
34
+ Puppet[:log_level] = :debug
35
+ resolvers = [DummyResolver.new(bad_service), DummyResolver.new(good_service)]
36
+ session = described_class.new(client, resolvers)
37
+ resolved = session.route_to(:ca)
38
+
39
+ expect(resolved).to eq(good_service)
40
+ expect(@logs).to include(an_object_having_attributes(level: :debug, message: "Connection to #{uri} failed, trying next route: whoops"))
41
+ end
42
+
43
+ it 'only resolves once per session' do
44
+ resolver = DummyResolver.new(good_service)
45
+ session = described_class.new(client, [resolver])
46
+ session.route_to(:ca)
47
+ session.route_to(:ca)
48
+
49
+ expect(resolver.count).to eq(1)
50
+ end
51
+
52
+ it 'raises if there are no more routes' do
53
+ resolvers = [DummyResolver.new(bad_service)]
54
+ session = described_class.new(client, resolvers)
55
+
56
+ expect {
57
+ session.route_to(:ca)
58
+ }.to raise_error(Puppet::HTTP::RouteError, 'No more routes to ca')
59
+ end
60
+
61
+ it 'accepts an ssl context to use when connecting' do
62
+ alt_context = Puppet::SSL::SSLContext.new
63
+ expect(good_service).to receive(:connect).with(ssl_context: alt_context)
64
+
65
+ resolvers = [DummyResolver.new(good_service)]
66
+ session = described_class.new(client, resolvers)
67
+ session.route_to(:ca, ssl_context: alt_context)
68
+ end
69
+
70
+ it 'raises for unknown service names' do
71
+ expect {
72
+ session = described_class.new(client, [])
73
+ session.route_to(:westbound)
74
+ }.to raise_error(ArgumentError, "Unknown service westbound")
75
+ end
76
+ end
77
+
78
+ context 'when creating services' do
79
+ let(:session) { described_class.new(client, []) }
80
+
81
+ it 'defaults the server and port based on settings' do
82
+ Puppet[:ca_server] = 'ca.example.com'
83
+ Puppet[:ca_port] = 8141
84
+ service = session.create_service(:ca)
85
+
86
+ expect(service.url.to_s).to eq("https://ca.example.com:8141/puppet-ca/v1")
87
+ end
88
+
89
+ it 'accepts server and port arguments' do
90
+ service = session.create_service(:ca, 'ca2.example.com', 8142)
91
+
92
+ expect(service.url.to_s).to eq("https://ca2.example.com:8142/puppet-ca/v1")
93
+ end
94
+
95
+ it 'raises for unknown service names' do
96
+ expect {
97
+ session = described_class.new(client, [])
98
+ session.create_service(:westbound)
99
+ }.to raise_error(ArgumentError, "Unknown service westbound")
100
+ end
101
+ end
102
+ end
@@ -48,7 +48,7 @@ describe "Puppet::Resource::Ral" do
48
48
  end
49
49
 
50
50
  it "should convert ral resources into regular resources" do
51
- my_resource = double("my user resource")
51
+ my_resource = double("my user resource", :title => "my user resource")
52
52
  my_instance = double("my user", :name => "root", :to_resource => my_resource)
53
53
 
54
54
  expect(Puppet::Type::User).to receive(:instances).and_return([ my_instance ])
@@ -56,7 +56,7 @@ describe "Puppet::Resource::Ral" do
56
56
  end
57
57
 
58
58
  it "should filter results by name if there's a name in the key" do
59
- my_resource = double("my user resource")
59
+ my_resource = double("my user resource", title: "my user resource")
60
60
  allow(my_resource).to receive(:to_resource).and_return(my_resource)
61
61
  allow(my_resource).to receive(:[]).with(:name).and_return("root")
62
62
 
@@ -74,11 +74,11 @@ describe "Puppet::Resource::Ral" do
74
74
  end
75
75
 
76
76
  it "should filter results by query parameters" do
77
- wrong_resource = double("my user resource")
77
+ wrong_resource = double("my user resource", title: "my user resource")
78
78
  allow(wrong_resource).to receive(:to_resource).and_return(wrong_resource)
79
79
  allow(wrong_resource).to receive(:[]).with(:name).and_return("root")
80
80
 
81
- my_resource = double("wrong resource")
81
+ my_resource = double("wrong resource", title: "wrong resource")
82
82
  allow(my_resource).to receive(:to_resource).and_return(my_resource)
83
83
  allow(my_resource).to receive(:[]).with(:name).and_return("bob")
84
84
 
@@ -4,10 +4,11 @@ require 'puppet_spec/validators'
4
4
  require 'puppet/test_ca'
5
5
 
6
6
  describe Puppet::Network::HTTP::Connection do
7
- let (:host) { "me" }
8
- let (:port) { 54321 }
7
+ let (:host) { "me.example.com" }
8
+ let (:port) { 8140 }
9
+ let (:url) { "https://#{host}:#{port}/foo" }
10
+
9
11
  subject { Puppet::Network::HTTP::Connection.new(host, port, :verify => Puppet::SSL::Validator.no_validator) }
10
- let (:httpok) { Net::HTTPOK.new('1.1', 200, '') }
11
12
 
12
13
  context "when providing HTTP connections" do
13
14
  context "when initializing http instances" do
@@ -68,68 +69,48 @@ describe Puppet::Network::HTTP::Connection do
68
69
  end
69
70
  end
70
71
 
71
- context "when handling requests", :vcr do
72
- let (:host) { "my-server" }
73
- let (:port) { 8140 }
74
- let (:subject) { Puppet::Network::HTTP::Connection.new(host, port, :use_ssl => false, :verify => Puppet::SSL::Validator.no_validator) }
75
-
76
- { :request_get => {},
77
- :request_head => {},
78
- :request_post => "param: value" }.each do |method,body|
79
- context "##{method}" do
80
- it "should yield to the block" do
81
- allow_any_instance_of(Net::HTTP).to receive(method) do |_, *_, &block|
82
- block.call()
83
- httpok
84
- end
85
-
86
- block_executed = false
87
- subject.send(method, "/foo", body) do |response|
88
- block_executed = true
89
- end
90
- expect(block_executed).to eq(true)
91
- end
92
- end
93
- end
94
- end
72
+ context "when handling requests" do
73
+ it 'yields the response when request_get is called' do
74
+ stub_request(:get, url)
95
75
 
96
- context "when response is a redirect" do
97
- let (:site) { Puppet::Network::HTTP::Site.new('http', 'my_server', 8140) }
98
- let (:other_site) { Puppet::Network::HTTP::Site.new('http', 'redirected', 9292) }
99
- let (:other_path) { "other-path" }
100
- let (:verify) { Puppet::SSL::Validator.no_validator }
101
- let (:subject) { Puppet::Network::HTTP::Connection.new(site.host, site.port, :use_ssl => false, :verify => verify) }
102
- let (:httpredirection) do
103
- response = Net::HTTPFound.new('1.1', 302, 'Moved Temporarily')
104
- response['location'] = "#{other_site.addr}/#{other_path}"
105
- allow(response).to receive(:read_body).and_return("This resource has moved")
106
- response
76
+ expect { |b|
77
+ subject.request_get('/foo', {}, &b)
78
+ }.to yield_with_args(Net::HTTPResponse)
107
79
  end
108
80
 
109
- def create_connection(site, options)
110
- options[:use_ssl] = site.use_ssl?
111
- Puppet::Network::HTTP::Connection.new(site.host, site.port, options)
81
+ it 'yields the response when request_head is called' do
82
+ stub_request(:head, url)
83
+
84
+ expect { |b|
85
+ subject.request_head('/foo', {}, &b)
86
+ }.to yield_with_args(Net::HTTPResponse)
112
87
  end
113
88
 
114
- it "should redirect to the final resource location" do
115
- http = double('http')
116
- allow(http).to receive(:request).and_return(httpredirection, httpok)
89
+ it 'yields the response when request_post is called' do
90
+ stub_request(:post, url)
117
91
 
118
- pool = Puppet.lookup(:http_pool)
119
- expect(pool).to receive(:with_connection).with(site, anything).and_yield(http).ordered
120
- expect(pool).to receive(:with_connection).with(other_site, anything).and_yield(http).ordered
92
+ expect { |b|
93
+ subject.request_post('/foo', "param: value", &b)
94
+ }.to yield_with_args(Net::HTTPResponse)
95
+ end
96
+ end
97
+
98
+ context "when response is a redirect" do
99
+ def create_connection(options = {})
100
+ options[:use_ssl] = false
101
+ options[:verify] = Puppet::SSL::Validator.no_validator
102
+ Puppet::Network::HTTP::Connection.new(host, port, options)
103
+ end
121
104
 
122
- conn = create_connection(site, :verify => verify)
123
- conn.get('/foo')
105
+ def redirect_to(url)
106
+ { status: 302, headers: { 'Location' => url } }
124
107
  end
125
108
 
126
- def expects_redirection(conn, &block)
127
- http = double('http')
128
- allow(http).to receive(:request).and_return(httpredirection)
109
+ it "should follow the redirect to the final resource location" do
110
+ stub_request(:get, "http://me.example.com:8140/foo").to_return(redirect_to("http://me.example.com:8140/bar"))
111
+ stub_request(:get, "http://me.example.com:8140/bar").to_return(status: 200)
129
112
 
130
- pool = Puppet.lookup(:http_pool)
131
- expect(pool).to receive(:with_connection).with(site, anything).and_yield(http)
132
- pool
113
+ create_connection.get('/foo')
133
114
  end
134
115
 
135
116
  def expects_limit_exceeded(conn)
@@ -138,164 +119,157 @@ describe Puppet::Network::HTTP::Connection do
138
119
  }.to raise_error(Puppet::Network::HTTP::RedirectionLimitExceededException)
139
120
  end
140
121
 
141
- it "should not redirect when the limit is 0" do
142
- conn = create_connection(site, :verify => verify, :redirect_limit => 0)
143
-
144
- pool = expects_redirection(conn)
145
- expect(pool).not_to receive(:with_connection).with(other_site, anything)
122
+ it "should not follow any redirects when the limit is 0" do
123
+ stub_request(:get, "http://me.example.com:8140/").to_return(redirect_to("http://me.example.com:8140/foo"))
146
124
 
125
+ conn = create_connection(:redirect_limit => 0)
147
126
  expects_limit_exceeded(conn)
148
127
  end
149
128
 
150
- it "should redirect only once" do
151
- conn = create_connection(site, :verify => verify, :redirect_limit => 1)
152
-
153
- pool = expects_redirection(conn)
154
- expect(pool).to receive(:with_connection).with(other_site, anything).once
129
+ it "should follow the redirect once" do
130
+ stub_request(:get, "http://me.example.com:8140/").to_return(redirect_to("http://me.example.com:8140/foo"))
131
+ stub_request(:get, "http://me.example.com:8140/foo").to_return(redirect_to("http://me.example.com:8140/bar"))
155
132
 
133
+ conn = create_connection(:redirect_limit => 1)
156
134
  expects_limit_exceeded(conn)
157
135
  end
158
136
 
159
137
  it "should raise an exception when the redirect limit is exceeded" do
160
- conn = create_connection(site, :verify => verify, :redirect_limit => 3)
161
-
162
- pool = expects_redirection(conn)
163
- expect(pool).to receive(:with_connection).with(other_site, anything).exactly(3).times
138
+ stub_request(:get, "http://me.example.com:8140/").to_return(redirect_to("http://me.example.com:8140/foo"))
139
+ stub_request(:get, "http://me.example.com:8140/foo").to_return(redirect_to("http://me.example.com:8140/bar"))
140
+ stub_request(:get, "http://me.example.com:8140/bar").to_return(redirect_to("http://me.example.com:8140/baz"))
141
+ stub_request(:get, "http://me.example.com:8140/baz").to_return(redirect_to("http://me.example.com:8140/qux"))
164
142
 
143
+ conn = create_connection(:redirect_limit => 3)
165
144
  expects_limit_exceeded(conn)
166
145
  end
167
146
  end
168
147
 
169
148
  context "when response indicates an overloaded server" do
170
- let(:http) { double('http') }
171
- let(:site) { Puppet::Network::HTTP::Site.new('http', 'my_server', 8140) }
172
- let(:verify) { Puppet::SSL::Validator.no_validator }
173
- let(:httpunavailable) { Net::HTTPServiceUnavailable.new('1.1', 503, 'Service Unavailable') }
174
-
175
- subject { Puppet::Network::HTTP::Connection.new(site.host, site.port, :use_ssl => false, :verify => verify) }
176
-
177
- context "when parsing Retry-After headers" do
178
- # Private method. Create a reference that can be called by tests.
179
- let(:header_parser) { subject.method(:parse_retry_after_header) }
180
-
181
- it "returns 0 when parsing a RFC 2822 date that has passed" do
182
- test_date = 'Wed, 13 Apr 2005 15:18:05 GMT'
183
-
184
- expect(header_parser.call(test_date)).to eq(0)
185
- end
149
+ def retry_after(datetime)
150
+ stub_request(:get, url)
151
+ .to_return(status: [503, 'Service Unavailable'], headers: {'Retry-After' => datetime}).then
152
+ .to_return(status: 200)
186
153
  end
187
154
 
188
155
  it "should return a 503 response if Retry-After is not set" do
189
- allow(http).to receive(:request).and_return(httpunavailable)
190
-
191
- pool = Puppet.lookup(:http_pool)
192
- expect(pool).to receive(:with_connection).with(site, anything).and_yield(http)
156
+ stub_request(:get, url).to_return(status: [503, 'Service Unavailable'])
193
157
 
194
158
  result = subject.get('/foo')
195
-
196
- expect(result.code).to eq(503)
159
+ expect(result.code).to eq("503")
197
160
  end
198
161
 
199
162
  it "should return a 503 response if Retry-After is not convertible to an Integer or RFC 2822 Date" do
200
- httpunavailable['Retry-After'] = 'foo'
201
- allow(http).to receive(:request).and_return(httpunavailable)
202
-
203
- pool = Puppet.lookup(:http_pool)
204
- expect(pool).to receive(:with_connection).with(site, anything).and_yield(http)
163
+ stub_request(:get, url).to_return(status: [503, 'Service Unavailable'], headers: {'Retry-After' => 'foo'})
205
164
 
206
165
  result = subject.get('/foo')
207
-
208
- expect(result.code).to eq(503)
166
+ expect(result.code).to eq("503")
209
167
  end
210
168
 
211
169
  it "should sleep and retry if Retry-After is an Integer" do
212
- httpunavailable['Retry-After'] = '42'
213
- allow(http).to receive(:request).and_return(httpunavailable, httpok)
214
-
215
- pool = Puppet.lookup(:http_pool)
216
- expect(pool).to receive(:with_connection).with(site, anything).twice.and_yield(http)
170
+ retry_after('42')
217
171
 
218
172
  expect(::Kernel).to receive(:sleep).with(42)
219
173
 
220
174
  result = subject.get('/foo')
221
-
222
- expect(result.code).to eq(200)
175
+ expect(result.code).to eq("200")
223
176
  end
224
177
 
225
178
  it "should sleep and retry if Retry-After is an RFC 2822 Date" do
226
- httpunavailable['Retry-After'] = 'Wed, 13 Apr 2005 15:18:05 GMT'
227
- allow(http).to receive(:request).and_return(httpunavailable, httpok)
179
+ retry_after('Wed, 13 Apr 2005 15:18:05 GMT')
228
180
 
229
181
  now = DateTime.new(2005, 4, 13, 8, 17, 5, '-07:00')
230
182
  allow(DateTime).to receive(:now).and_return(now)
231
183
 
232
- pool = Puppet.lookup(:http_pool)
233
- expect(pool).to receive(:with_connection).with(site, anything).twice.and_yield(http)
234
-
235
184
  expect(::Kernel).to receive(:sleep).with(60)
236
185
 
237
186
  result = subject.get('/foo')
238
-
239
- expect(result.code).to eq(200)
187
+ expect(result.code).to eq("200")
240
188
  end
241
189
 
242
190
  it "should sleep for no more than the Puppet runinterval" do
243
- httpunavailable['Retry-After'] = '60'
244
- allow(http).to receive(:request).and_return(httpunavailable, httpok)
191
+ retry_after('60')
245
192
  Puppet[:runinterval] = 30
246
193
 
247
- pool = Puppet.lookup(:http_pool)
248
- expect(pool).to receive(:with_connection).with(site, anything).twice.and_yield(http)
249
-
250
194
  expect(::Kernel).to receive(:sleep).with(30)
251
195
 
252
196
  subject.get('/foo')
253
197
  end
254
- end
255
198
 
256
- it "allows setting basic auth on get requests" do
257
- expect_request_with_basic_auth
199
+ it "should sleep for 0 seconds if the RFC 2822 date has past" do
200
+ retry_after('Wed, 13 Apr 2005 15:18:05 GMT')
201
+
202
+ expect(::Kernel).to receive(:sleep).with(0)
258
203
 
259
- subject.get('/path', nil, :basic_auth => { :user => 'user', :password => 'password' })
204
+ subject.get('/foo')
205
+ end
260
206
  end
261
207
 
262
- it "allows setting basic auth on post requests" do
263
- expect_request_with_basic_auth
208
+ context "basic auth" do
209
+ let(:auth) { { :user => 'user', :password => 'password' } }
210
+ let(:creds) { [ 'user', 'password'] }
264
211
 
265
- subject.post('/path', 'data', nil, :basic_auth => { :user => 'user', :password => 'password' })
266
- end
212
+ it "is allowed in get requests" do
213
+ stub_request(:get, url).with(basic_auth: creds)
267
214
 
268
- it "allows setting basic auth on head requests" do
269
- expect_request_with_basic_auth
215
+ subject.get('/foo', nil, :basic_auth => auth)
216
+ end
270
217
 
271
- subject.head('/path', nil, :basic_auth => { :user => 'user', :password => 'password' })
272
- end
218
+ it "is allowed in post requests" do
219
+ stub_request(:post, url).with(basic_auth: creds)
273
220
 
274
- it "allows setting basic auth on delete requests" do
275
- expect_request_with_basic_auth
221
+ subject.post('/foo', 'data', nil, :basic_auth => auth)
222
+ end
276
223
 
277
- subject.delete('/path', nil, :basic_auth => { :user => 'user', :password => 'password' })
278
- end
224
+ it "is allowed in head requests" do
225
+ stub_request(:head, url).with(basic_auth: creds)
279
226
 
280
- it "allows setting basic auth on put requests" do
281
- expect_request_with_basic_auth
227
+ subject.head('/foo', nil, :basic_auth => auth)
228
+ end
282
229
 
283
- subject.put('/path', 'data', nil, :basic_auth => { :user => 'user', :password => 'password' })
284
- end
230
+ it "is allowed in delete requests" do
231
+ stub_request(:delete, url).with(basic_auth: creds)
285
232
 
286
- def expect_request_with_basic_auth
287
- expect_any_instance_of(Net::HTTP).to receive(:request) do |_, request|
288
- expect(request['authorization']).to match(/^Basic/)
289
- end.and_return(httpok)
233
+ subject.delete('/foo', nil, :basic_auth => auth)
234
+ end
235
+
236
+ it "is allowed in put requests" do
237
+ stub_request(:put, url).with(basic_auth: creds)
238
+
239
+ subject.put('/foo', 'data', nil, :basic_auth => auth)
240
+ end
290
241
  end
291
242
 
292
243
  it "sets HTTP User-Agent header" do
293
244
  puppet_ua = "Puppet/#{Puppet.version} Ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} (#{RUBY_PLATFORM})"
245
+ stub_request(:get, url).with(headers: { 'User-Agent' => puppet_ua })
294
246
 
295
- expect_any_instance_of(Net::HTTP).to receive(:request) do |_, request|
296
- expect(request['User-Agent']).to eq(puppet_ua)
297
- end.and_return(httpok)
247
+ subject.get('/foo')
248
+ end
249
+
250
+ describe 'connection request errors' do
251
+ it "logs and raises generic http errors" do
252
+ generic_error = Net::HTTPError.new('generic error', double("response"))
253
+ stub_request(:get, url).to_raise(generic_error)
298
254
 
299
- subject.get('/path')
255
+ expect(Puppet).to receive(:log_exception).with(anything, /^.*failed: generic error$/)
256
+ expect { subject.get('/foo') }.to raise_error(generic_error)
257
+ end
258
+
259
+ it "logs and raises timeout errors" do
260
+ timeout_error = Timeout::Error.new
261
+ stub_request(:get, url).to_raise(timeout_error)
262
+
263
+ expect(Puppet).to receive(:log_exception).with(anything, /^.*timed out after .* seconds$/)
264
+ expect { subject.get('/foo') }.to raise_error(timeout_error)
265
+ end
266
+
267
+ it "logs and raises eof errors" do
268
+ eof_error = EOFError
269
+ stub_request(:get, url).to_raise(eof_error)
270
+
271
+ expect(Puppet).to receive(:log_exception).with(anything, /^.*interrupted after .* seconds$/)
272
+ expect { subject.get('/foo') }.to raise_error(eof_error)
273
+ end
300
274
  end
301
275
  end