puppet 6.14.0 → 6.15.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 (195) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +15 -15
  3. data/ext/windows/service/daemon.rb +3 -3
  4. data/lib/puppet.rb +1 -1
  5. data/lib/puppet/agent.rb +2 -10
  6. data/lib/puppet/application/agent.rb +2 -1
  7. data/lib/puppet/application/filebucket.rb +5 -14
  8. data/lib/puppet/application/ssl.rb +2 -2
  9. data/lib/puppet/configurer.rb +7 -3
  10. data/lib/puppet/configurer/plugin_handler.rb +1 -1
  11. data/lib/puppet/defaults.rb +22 -2
  12. data/lib/puppet/environments.rb +4 -5
  13. data/lib/puppet/face/plugin.rb +1 -1
  14. data/lib/puppet/file_system/file_impl.rb +13 -9
  15. data/lib/puppet/forge/repository.rb +1 -1
  16. data/lib/puppet/functions/call.rb +1 -1
  17. data/lib/puppet/functions/reduce.rb +2 -4
  18. data/lib/puppet/http.rb +2 -0
  19. data/lib/puppet/http/client.rb +191 -52
  20. data/lib/puppet/http/external_client.rb +96 -0
  21. data/lib/puppet/http/redirector.rb +34 -0
  22. data/lib/puppet/http/resolver.rb +46 -3
  23. data/lib/puppet/http/resolver/server_list.rb +75 -15
  24. data/lib/puppet/http/resolver/settings.rb +22 -2
  25. data/lib/puppet/http/resolver/srv.rb +28 -2
  26. data/lib/puppet/http/response.rb +63 -1
  27. data/lib/puppet/http/retry_after_handler.rb +39 -0
  28. data/lib/puppet/http/service.rb +67 -1
  29. data/lib/puppet/http/service/ca.rb +71 -9
  30. data/lib/puppet/http/service/compiler.rb +213 -11
  31. data/lib/puppet/http/service/file_server.rb +105 -4
  32. data/lib/puppet/http/service/report.rb +36 -3
  33. data/lib/puppet/http/session.rb +59 -8
  34. data/lib/puppet/indirector/catalog/rest.rb +2 -1
  35. data/lib/puppet/indirector/facts/rest.rb +2 -1
  36. data/lib/puppet/indirector/file_bucket_file/rest.rb +48 -0
  37. data/lib/puppet/indirector/file_metadata/rest.rb +4 -2
  38. data/lib/puppet/indirector/node/rest.rb +2 -1
  39. data/lib/puppet/indirector/report/yaml.rb +23 -0
  40. data/lib/puppet/indirector/status/rest.rb +2 -1
  41. data/lib/puppet/metatype/manager.rb +80 -80
  42. data/lib/puppet/network/http/base_pool.rb +6 -1
  43. data/lib/puppet/network/http/pool.rb +2 -4
  44. data/lib/puppet/network/http_pool.rb +1 -0
  45. data/lib/puppet/node/environment.rb +11 -1
  46. data/lib/puppet/pal/pal_impl.rb +1 -29
  47. data/lib/puppet/parser/compiler.rb +14 -7
  48. data/lib/puppet/parser/functions.rb +18 -13
  49. data/lib/puppet/pops/loaders.rb +7 -5
  50. data/lib/puppet/provider/group/windows_adsi.rb +3 -3
  51. data/lib/puppet/provider/package/apt.rb +61 -1
  52. data/lib/puppet/provider/package/dnfmodule.rb +39 -12
  53. data/lib/puppet/provider/package/gem.rb +41 -7
  54. data/lib/puppet/provider/package/pacman.rb +2 -5
  55. data/lib/puppet/provider/package/pip.rb +105 -33
  56. data/lib/puppet/provider/package/pip3.rb +0 -2
  57. data/lib/puppet/provider/package/pkgdmg.rb +1 -1
  58. data/lib/puppet/provider/package/pkgng.rb +16 -4
  59. data/lib/puppet/provider/package/puppet_gem.rb +6 -2
  60. data/lib/puppet/provider/package/rpm.rb +6 -213
  61. data/lib/puppet/provider/package/yum.rb +92 -19
  62. data/lib/puppet/provider/service/systemd.rb +2 -1
  63. data/lib/puppet/reports/http.rb +13 -11
  64. data/lib/puppet/resource/type_collection.rb +20 -16
  65. data/lib/puppet/ssl.rb +1 -0
  66. data/lib/puppet/ssl/host.rb +4 -4
  67. data/lib/puppet/ssl/oids.rb +1 -0
  68. data/lib/puppet/ssl/state_machine.rb +50 -33
  69. data/lib/puppet/transaction/report.rb +2 -2
  70. data/lib/puppet/type.rb +6 -1
  71. data/lib/puppet/type/file/source.rb +4 -2
  72. data/lib/puppet/type/package.rb +25 -2
  73. data/lib/puppet/type/user.rb +0 -19
  74. data/lib/puppet/util/at_fork.rb +1 -1
  75. data/lib/puppet/util/autoload.rb +3 -0
  76. data/lib/puppet/util/instance_loader.rb +14 -10
  77. data/lib/puppet/util/package/version/debian.rb +175 -0
  78. data/lib/puppet/util/package/version/gem.rb +15 -0
  79. data/lib/puppet/util/package/version/pip.rb +167 -0
  80. data/lib/puppet/util/package/version/range.rb +50 -0
  81. data/lib/puppet/util/package/version/range/gt.rb +14 -0
  82. data/lib/puppet/util/package/version/range/gt_eq.rb +14 -0
  83. data/lib/puppet/util/package/version/range/lt.rb +14 -0
  84. data/lib/puppet/util/package/version/range/lt_eq.rb +14 -0
  85. data/lib/puppet/util/package/version/range/min_max.rb +21 -0
  86. data/lib/puppet/util/package/version/range/simple.rb +11 -0
  87. data/lib/puppet/util/package/version/rpm.rb +73 -0
  88. data/lib/puppet/util/pidlock.rb +13 -7
  89. data/lib/puppet/util/platform.rb +5 -0
  90. data/lib/puppet/util/rpm_compare.rb +193 -0
  91. data/lib/puppet/util/windows/adsi.rb +2 -2
  92. data/lib/puppet/util/windows/process.rb +15 -14
  93. data/lib/puppet/util/windows/security.rb +1 -0
  94. data/lib/puppet/util/windows/sid.rb +3 -3
  95. data/lib/puppet/version.rb +1 -1
  96. data/locales/puppet.pot +207 -201
  97. data/man/man5/puppet.conf.5 +11 -3
  98. data/man/man8/puppet-agent.8 +1 -1
  99. data/man/man8/puppet-apply.8 +1 -1
  100. data/man/man8/puppet-catalog.8 +1 -1
  101. data/man/man8/puppet-config.8 +1 -1
  102. data/man/man8/puppet-describe.8 +1 -1
  103. data/man/man8/puppet-device.8 +1 -1
  104. data/man/man8/puppet-doc.8 +1 -1
  105. data/man/man8/puppet-epp.8 +1 -1
  106. data/man/man8/puppet-facts.8 +1 -1
  107. data/man/man8/puppet-filebucket.8 +1 -1
  108. data/man/man8/puppet-generate.8 +1 -1
  109. data/man/man8/puppet-help.8 +1 -1
  110. data/man/man8/puppet-key.8 +1 -1
  111. data/man/man8/puppet-lookup.8 +1 -1
  112. data/man/man8/puppet-man.8 +1 -1
  113. data/man/man8/puppet-module.8 +1 -1
  114. data/man/man8/puppet-node.8 +1 -1
  115. data/man/man8/puppet-parser.8 +1 -1
  116. data/man/man8/puppet-plugin.8 +1 -1
  117. data/man/man8/puppet-report.8 +1 -1
  118. data/man/man8/puppet-resource.8 +1 -1
  119. data/man/man8/puppet-script.8 +1 -1
  120. data/man/man8/puppet-ssl.8 +1 -1
  121. data/man/man8/puppet-status.8 +1 -1
  122. data/man/man8/puppet.8 +2 -2
  123. data/spec/fixtures/ssl/unknown-127.0.0.1-key.pem +67 -0
  124. data/spec/fixtures/ssl/unknown-127.0.0.1.pem +48 -0
  125. data/spec/fixtures/ssl/unknown-ca-key.pem +67 -0
  126. data/spec/fixtures/ssl/unknown-ca.pem +59 -0
  127. data/spec/fixtures/unit/provider/package/dnfmodule/{dnf-module-list-installed.txt → dnf-module-list-enabled.txt} +2 -0
  128. data/spec/fixtures/unit/provider/package/pkgng/pkg.version +2 -0
  129. data/spec/fixtures/unit/provider/package/yum/yum-check-update-subscription-manager.txt +9 -0
  130. data/spec/fixtures/unit/provider/service/systemd/list_unit_files_services +9 -0
  131. data/spec/integration/application/agent_spec.rb +329 -0
  132. data/spec/integration/application/apply_spec.rb +132 -3
  133. data/spec/integration/application/filebucket_spec.rb +190 -0
  134. data/spec/integration/application/plugin_spec.rb +50 -0
  135. data/spec/integration/http/client_spec.rb +34 -40
  136. data/spec/integration/indirector/report/yaml.rb +83 -0
  137. data/spec/integration/module_tool/forge_spec.rb +2 -15
  138. data/spec/integration/network/http_pool_spec.rb +11 -19
  139. data/spec/integration/node/environment_spec.rb +15 -0
  140. data/spec/integration/util/windows/adsi_spec.rb +1 -1
  141. data/spec/lib/puppet/test_ca.rb +2 -2
  142. data/spec/lib/puppet_spec/https.rb +10 -7
  143. data/spec/lib/puppet_spec/puppetserver.rb +119 -0
  144. data/spec/shared_contexts/https.rb +29 -0
  145. data/spec/unit/agent_spec.rb +33 -25
  146. data/spec/unit/application/agent_spec.rb +5 -1
  147. data/spec/unit/application/device_spec.rb +2 -2
  148. data/spec/unit/application/filebucket_spec.rb +22 -2
  149. data/spec/unit/configurer_spec.rb +1 -1
  150. data/spec/unit/defaults_spec.rb +24 -1
  151. data/spec/unit/environments_spec.rb +8 -0
  152. data/spec/unit/file_system_spec.rb +10 -0
  153. data/spec/unit/http/client_spec.rb +105 -46
  154. data/spec/unit/http/external_client_spec.rb +201 -0
  155. data/spec/unit/http/resolver_spec.rb +20 -0
  156. data/spec/unit/http/service/ca_spec.rb +25 -2
  157. data/spec/unit/http/service/compiler_spec.rb +184 -6
  158. data/spec/unit/http/service/file_server_spec.rb +35 -3
  159. data/spec/unit/http/service/report_spec.rb +3 -1
  160. data/spec/unit/http/service_spec.rb +3 -3
  161. data/spec/unit/http/session_spec.rb +56 -7
  162. data/spec/unit/indirector/file_bucket_file/rest_spec.rb +82 -2
  163. data/spec/unit/network/http/pool_spec.rb +3 -3
  164. data/spec/unit/node/environment_spec.rb +16 -0
  165. data/spec/unit/provider/group/windows_adsi_spec.rb +43 -10
  166. data/spec/unit/provider/package/apt_spec.rb +30 -0
  167. data/spec/unit/provider/package/dnfmodule_spec.rb +33 -14
  168. data/spec/unit/provider/package/gem_spec.rb +40 -0
  169. data/spec/unit/provider/package/pacman_spec.rb +6 -21
  170. data/spec/unit/provider/package/pip_spec.rb +26 -3
  171. data/spec/unit/provider/package/pkgdmg_spec.rb +1 -1
  172. data/spec/unit/provider/package/pkgng_spec.rb +38 -0
  173. data/spec/unit/provider/package/puppet_gem_spec.rb +8 -0
  174. data/spec/unit/provider/package/rpm_spec.rb +0 -212
  175. data/spec/unit/provider/package/yum_spec.rb +235 -1
  176. data/spec/unit/provider/service/systemd_spec.rb +10 -1
  177. data/spec/unit/provider/user/windows_adsi_spec.rb +3 -3
  178. data/spec/unit/puppet_pal_2pec.rb +0 -29
  179. data/spec/unit/reports/http_spec.rb +70 -52
  180. data/spec/unit/ssl/host_spec.rb +4 -2
  181. data/spec/unit/ssl/oids_spec.rb +1 -0
  182. data/spec/unit/ssl/state_machine_spec.rb +38 -6
  183. data/spec/unit/transaction/report_spec.rb +4 -0
  184. data/spec/unit/util/at_fork_spec.rb +2 -2
  185. data/spec/unit/util/package/version/debian_spec.rb +83 -0
  186. data/spec/unit/util/package/version/pip_spec.rb +464 -0
  187. data/spec/unit/util/package/version/range_spec.rb +154 -0
  188. data/spec/unit/util/package/version/rpm_spec.rb +121 -0
  189. data/spec/unit/util/pidlock_spec.rb +83 -47
  190. data/spec/unit/util/rpm_compare_spec.rb +196 -0
  191. data/spec/unit/util/windows/adsi_spec.rb +4 -4
  192. data/spec/unit/util/windows/sid_spec.rb +2 -2
  193. data/tasks/generate_cert_fixtures.rake +15 -1
  194. metadata +51 -6
  195. data/spec/integration/faces/plugin_spec.rb +0 -63
@@ -114,12 +114,31 @@ describe Puppet::Application::Filebucket do
114
114
  @filebucket.setup
115
115
  end
116
116
 
117
- it "should default to the first server_list entry if set" do
117
+ it "should default to the first good server_list entry if server_list is set" do
118
+ stub_request(:get, "https://foo:8140/status/v1/simple/master").to_return(status: 200)
118
119
  Puppet[:server_list] = "foo,bar,baz"
119
120
  expect(Puppet::FileBucket::Dipper).to receive(:new).with(hash_including(Server: "foo"))
120
121
  @filebucket.setup
121
122
  end
122
123
 
124
+ it "should walk server_list until it finds a good entry" do
125
+ stub_request(:get, "https://foo:8140/status/v1/simple/master").to_return(status: 502)
126
+ stub_request(:get, "https://bar:8140/status/v1/simple/master").to_return(status: 200)
127
+ Puppet[:server_list] = "foo,bar,baz"
128
+ expect(Puppet::FileBucket::Dipper).to receive(:new).with(hash_including(Server: "bar"))
129
+ @filebucket.setup
130
+ end
131
+
132
+ # FileBucket catches any exceptions raised, logs them, then just exits
133
+ it "raises an error if there are no functional servers in server_list" do
134
+ stub_request(:get, "https://foo:8140/status/v1/simple/master").to_return(status: 404)
135
+ stub_request(:get, "https://bar:8140/status/v1/simple/master").to_return(status: 404)
136
+ Puppet[:server] = 'horacio'
137
+ Puppet[:server_list] = "foo,bar"
138
+
139
+ expect{@filebucket.setup}.to exit_with(1)
140
+ end
141
+
123
142
  it "should fall back to server if server_list is empty" do
124
143
  Puppet[:server_list] = ""
125
144
  expect(Puppet::FileBucket::Dipper).to receive(:new).with(hash_including(Server: "puppet"))
@@ -127,8 +146,9 @@ describe Puppet::Application::Filebucket do
127
146
  end
128
147
 
129
148
  it "should take both the server and port specified in server_list" do
149
+ stub_request(:get, "https://foo:632/status/v1/simple/master").to_return(status: 200)
130
150
  Puppet[:server_list] = "foo:632,bar:6215,baz:351"
131
- expect(Puppet::FileBucket::Dipper).to receive(:new).with({ :Server => "foo", :Port => "632" })
151
+ expect(Puppet::FileBucket::Dipper).to receive(:new).with({ :Server => "foo", :Port => 632 })
132
152
  @filebucket.setup
133
153
  end
134
154
  end
@@ -148,7 +148,7 @@ describe Puppet::Configurer do
148
148
  configurer = Puppet::Configurer.new("test_tuuid", "test_jid")
149
149
 
150
150
  report = Puppet::Transaction::Report.new(nil, "test", "aaaa")
151
- expect(Puppet::Transaction::Report).to receive(:new).with(anything, anything, 'test_tuuid', 'test_jid').and_return(report)
151
+ expect(Puppet::Transaction::Report).to receive(:new).with(anything, anything, 'test_tuuid', 'test_jid', anything).and_return(report)
152
152
  expect(configurer).to receive(:send_report).with(report)
153
153
 
154
154
  configurer.run
@@ -188,8 +188,31 @@ describe "Defaults" do
188
188
  end
189
189
 
190
190
  it "raises an exception if facter-ng could not be loaded" do
191
- allow(Puppet).to receive(:require).with('facter-ng').and_return(false)
191
+ allow_any_instance_of(Puppet::Settings::BooleanSetting).to receive(:require).with('facter-ng').and_raise(LoadError)
192
+
192
193
  expect{ Puppet.settings[:facterng] = true }.to raise_exception ArgumentError, 'facter-ng could not be loaded'
193
194
  end
195
+
196
+ context 'set logger' do
197
+ before do
198
+ @original_facter = Object.const_get(:Facter)
199
+
200
+ Object.send(:remove_const, :Facter)
201
+ Object.const_set(:Facter, Module.new)
202
+
203
+ allow_any_instance_of(Puppet::Settings::BooleanSetting).to receive(:require).with('facter-ng').and_return(true)
204
+ allow(Facter).to receive(:respond_to?).and_return(false)
205
+ end
206
+
207
+ after do
208
+ Object.const_set(:Facter, @original_facter)
209
+ end
210
+
211
+ it 'calls setup_facter_logging!' do
212
+ allow(Puppet::Util::Logging).to receive(:setup_facter_logging!).and_return(true)
213
+ Puppet.settings[:facterng] = true
214
+ expect(Puppet::Util::Logging).to have_received(:setup_facter_logging!).once
215
+ end
216
+ end
194
217
  end
195
218
  end
@@ -35,6 +35,7 @@ describe Puppet::Environments do
35
35
  FS::MemoryFile.a_directory("modules"),
36
36
  FS::MemoryFile.a_directory("manifests"),
37
37
  ]),
38
+ FS::MemoryFile.a_missing_file("missing")
38
39
  ])
39
40
  end
40
41
 
@@ -90,6 +91,13 @@ describe Puppet::Environments do
90
91
  end
91
92
  end
92
93
 
94
+ it "proceeds with non-existant env dir" do
95
+ loader_from(:filesystem => [directory_tree],
96
+ :directory => directory_tree.children.last) do |loader|
97
+ expect(loader.list).to eq([])
98
+ end
99
+ end
100
+
93
101
  it "gets a particular environment" do
94
102
  loader_from(:filesystem => [directory_tree],
95
103
  :directory => directory_tree.children.first) do |loader|
@@ -970,6 +970,16 @@ describe "Puppet::FileSystem" do
970
970
  mode = Puppet::FileSystem.stat(dest).mode
971
971
  expect(mode & 07777).to eq(0400)
972
972
  end
973
+
974
+ it 'preserves file ownership' do
975
+ allow(Puppet::FileSystem).to receive(:lstat)
976
+ .with(Puppet::FileSystem.pathname(dest))
977
+ .and_return(double(uid: 1, gid: 2))
978
+
979
+ expect(FileUtils).to receive(:chown).with(1, 2, /#{dest}/)
980
+
981
+ Puppet::FileSystem.replace_file(dest, 0644) { |f| f.write(content) }
982
+ end
973
983
  end
974
984
 
975
985
  context 'on windows', if: Puppet::Util::Platform.windows? do
@@ -4,10 +4,9 @@ require 'puppet/http'
4
4
 
5
5
  describe Puppet::HTTP::Client do
6
6
  let(:uri) { URI.parse('https://www.example.com') }
7
- let(:pool) { Puppet::Network::HTTP::Pool.new }
8
7
  let(:puppet_context) { Puppet::SSL::SSLContext.new }
9
8
  let(:system_context) { Puppet::SSL::SSLContext.new }
10
- let(:client) { described_class.new(pool: pool, ssl_context: puppet_context, system_ssl_context: system_context) }
9
+ let(:client) { described_class.new(ssl_context: puppet_context, system_ssl_context: system_context) }
11
10
  let(:credentials) { ['user', 'pass'] }
12
11
 
13
12
  it 'creates unique sessions' do
@@ -50,7 +49,7 @@ describe Puppet::HTTP::Client do
50
49
  end
51
50
 
52
51
  it 'connects using the default ssl context' do
53
- expect(pool).to receive(:with_connection) do |_, verifier|
52
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
54
53
  expect(verifier.ssl_context).to equal(puppet_context)
55
54
  end
56
55
 
@@ -60,24 +59,32 @@ describe Puppet::HTTP::Client do
60
59
  it 'connects using a specified ssl context' do
61
60
  other_context = Puppet::SSL::SSLContext.new
62
61
 
63
- expect(pool).to receive(:with_connection) do |_, verifier|
62
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
64
63
  expect(verifier.ssl_context).to equal(other_context)
65
64
  end
66
65
 
67
- client.connect(uri, ssl_context: other_context)
66
+ client.connect(uri, options: {ssl_context: other_context})
68
67
  end
69
68
 
70
69
  it 'connects using the system store' do
71
- expect(pool).to receive(:with_connection) do |_, verifier|
70
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
72
71
  expect(verifier.ssl_context).to equal(system_context)
73
72
  end
74
73
 
75
- client.connect(uri, include_system_store: true)
74
+ client.connect(uri, options: {include_system_store: true})
75
+ end
76
+
77
+ it 'does not create a verifier for HTTP connections' do
78
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
79
+ expect(verifier).to be_nil
80
+ end
81
+
82
+ client.connect(URI.parse('http://www.example.com'))
76
83
  end
77
84
 
78
85
  it 'raises an HTTPError if both are specified' do
79
86
  expect {
80
- client.connect(uri, ssl_context: puppet_context, include_system_store: true)
87
+ client.connect(uri, options: {ssl_context: puppet_context, include_system_store: true})
81
88
  }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
82
89
  end
83
90
  end
@@ -110,10 +117,8 @@ describe Puppet::HTTP::Client do
110
117
 
111
118
  context "when closing" do
112
119
  it "closes all connections in the pool" do
113
- pool = double('pool')
114
- expect(pool).to receive(:close)
120
+ expect(client.pool).to receive(:close)
115
121
 
116
- client = described_class.new(pool: pool)
117
122
  client.close
118
123
  end
119
124
  end
@@ -180,18 +185,18 @@ describe Puppet::HTTP::Client do
180
185
 
181
186
  other_context = Puppet::SSL::SSLContext.new
182
187
 
183
- client.get(uri, ssl_context: other_context)
188
+ client.get(uri, options: {ssl_context: other_context})
184
189
  end
185
190
 
186
191
  it 'uses the system store' do
187
192
  stub_request(:get, uri).to_return(body: "abc")
188
193
 
189
- client.get(uri, include_system_store: true)
194
+ client.get(uri, options: {include_system_store: true})
190
195
  end
191
196
 
192
197
  it 'raises an HTTPError if both are specified' do
193
198
  expect {
194
- client.get(uri, ssl_context: puppet_context, include_system_store: true)
199
+ client.get(uri, options: {ssl_context: puppet_context, include_system_store: true})
195
200
  }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
196
201
  end
197
202
  end
@@ -237,18 +242,18 @@ describe Puppet::HTTP::Client do
237
242
 
238
243
  other_context = Puppet::SSL::SSLContext.new
239
244
 
240
- client.head(uri, ssl_context: other_context)
245
+ client.head(uri, options: {ssl_context: other_context})
241
246
  end
242
247
 
243
248
  it 'uses the system store' do
244
249
  stub_request(:head, uri)
245
250
 
246
- client.head(uri, include_system_store: true)
251
+ client.head(uri, options: {include_system_store: true})
247
252
  end
248
253
 
249
254
  it 'raises an HTTPError if both are specified' do
250
255
  expect {
251
- client.head(uri, ssl_context: puppet_context, include_system_store: true)
256
+ client.head(uri, options: {ssl_context: puppet_context, include_system_store: true})
252
257
  }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
253
258
  end
254
259
  end
@@ -261,25 +266,25 @@ describe Puppet::HTTP::Client do
261
266
  expect(request.headers).to_not include('X-Puppet-Profiling')
262
267
  end
263
268
 
264
- client.put(uri, content_type: 'text/plain', body: "")
269
+ client.put(uri, "", headers: {'Content-Type' => 'text/plain'})
265
270
  end
266
271
 
267
272
  it "stringifies keys and encodes values in the query" do
268
273
  stub_request(:put, "https://www.example.com").with(query: "foo=bar%3Dbaz")
269
274
 
270
- client.put(uri, params: {:foo => "bar=baz"}, content_type: 'text/plain', body: "")
275
+ client.put(uri, "", params: {:foo => "bar=baz"}, headers: {'Content-Type' => 'text/plain'})
271
276
  end
272
277
 
273
278
  it "includes custom headers" do
274
279
  stub_request(:put, "https://www.example.com").with(headers: { 'X-Foo' => 'Bar' })
275
280
 
276
- client.put(uri, headers: {'X-Foo' => 'Bar'}, content_type: 'text/plain', body: "")
281
+ client.put(uri, "", headers: {'X-Foo' => 'Bar', 'Content-Type' => 'text/plain'})
277
282
  end
278
283
 
279
284
  it "returns the response" do
280
285
  stub_request(:put, uri)
281
286
 
282
- response = client.put(uri, content_type: 'text/plain', body: "")
287
+ response = client.put(uri, "", headers: {'Content-Type' => 'text/plain'})
283
288
  expect(response).to be_an_instance_of(Puppet::HTTP::Response)
284
289
  expect(response).to be_success
285
290
  expect(response.code).to eq(200)
@@ -288,27 +293,39 @@ describe Puppet::HTTP::Client do
288
293
  it "sets content-length and content-type for the body" do
289
294
  stub_request(:put, uri).with(headers: {"Content-Length" => "5", "Content-Type" => "text/plain"})
290
295
 
291
- client.put(uri, content_type: 'text/plain', body: "hello")
296
+ client.put(uri, "hello", headers: {'Content-Type' => 'text/plain'})
292
297
  end
293
298
 
299
+ it 'raises an ArgumentError if `body` is missing' do
300
+ expect {
301
+ client.put(uri, nil, headers: {'Content-Type' => 'text/plain'})
302
+ }.to raise_error(ArgumentError, /'put' requires a string 'body' argument/)
303
+ end
304
+
305
+ it 'raises an ArgumentError if `content_type` is missing from the headers hash' do
306
+ expect {
307
+ client.put(uri, '')
308
+ }.to raise_error(ArgumentError, /'put' requires a 'content-type' header/)
309
+ end
310
+
294
311
  context 'when connecting' do
295
312
  it 'uses a specified ssl context' do
296
313
  stub_request(:put, uri)
297
314
 
298
315
  other_context = Puppet::SSL::SSLContext.new
299
316
 
300
- client.put(uri, content_type: 'text/plain', body: "", ssl_context: other_context)
317
+ client.put(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {ssl_context: other_context})
301
318
  end
302
319
 
303
320
  it 'uses the system store' do
304
321
  stub_request(:put, uri)
305
322
 
306
- client.put(uri, content_type: 'text/plain', body: "", include_system_store: true)
323
+ client.put(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {include_system_store: true})
307
324
  end
308
325
 
309
326
  it 'raises an HTTPError if both are specified' do
310
327
  expect {
311
- client.put(uri, content_type: 'text/plain', body: "", ssl_context: puppet_context, include_system_store: true)
328
+ client.put(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {ssl_context: puppet_context, include_system_store: true})
312
329
  }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
313
330
  end
314
331
  end
@@ -318,25 +335,25 @@ describe Puppet::HTTP::Client do
318
335
  it "includes default HTTP headers" do
319
336
  stub_request(:post, uri).with(headers: {'X-Puppet-Version' => /./, 'User-Agent' => /./})
320
337
 
321
- client.post(uri, content_type: 'text/plain', body: "")
338
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'})
322
339
  end
323
340
 
324
341
  it "stringifies keys and encodes values in the query" do
325
342
  stub_request(:post, "https://www.example.com").with(query: "foo=bar%3Dbaz")
326
343
 
327
- client.post(uri, params: {:foo => "bar=baz"}, content_type: 'text/plain', body: "")
344
+ client.post(uri, "", params: {:foo => "bar=baz"}, headers: {'Content-Type' => 'text/plain'})
328
345
  end
329
346
 
330
347
  it "includes custom headers" do
331
348
  stub_request(:post, "https://www.example.com").with(headers: { 'X-Foo' => 'Bar' })
332
349
 
333
- client.post(uri, headers: {'X-Foo' => 'Bar'}, content_type: 'text/plain', body: "")
350
+ client.post(uri, "", headers: {'X-Foo' => 'Bar', 'Content-Type' => 'text/plain'})
334
351
  end
335
352
 
336
353
  it "returns the response" do
337
354
  stub_request(:post, uri)
338
355
 
339
- response = client.post(uri, content_type: 'text/plain', body: "")
356
+ response = client.post(uri, "", headers: {'Content-Type' => 'text/plain'})
340
357
  expect(response).to be_an_instance_of(Puppet::HTTP::Response)
341
358
  expect(response).to be_success
342
359
  expect(response.code).to eq(200)
@@ -345,14 +362,14 @@ describe Puppet::HTTP::Client do
345
362
  it "sets content-length and content-type for the body" do
346
363
  stub_request(:post, uri).with(headers: {"Content-Length" => "5", "Content-Type" => "text/plain"})
347
364
 
348
- client.post(uri, content_type: 'text/plain', body: "hello")
365
+ client.post(uri, "hello", headers: {'Content-Type' => 'text/plain'})
349
366
  end
350
367
 
351
368
  it "streams the response body when a block is given" do
352
369
  stub_request(:post, uri).to_return(body: "abc")
353
370
 
354
371
  io = StringIO.new
355
- client.post(uri, content_type: 'text/plain', body: "") do |response|
372
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}) do |response|
356
373
  response.read_body do |data|
357
374
  io.write(data)
358
375
  end
@@ -361,24 +378,36 @@ describe Puppet::HTTP::Client do
361
378
  expect(io.string).to eq("abc")
362
379
  end
363
380
 
381
+ it 'raises an ArgumentError if `body` is missing' do
382
+ expect {
383
+ client.post(uri, nil, headers: {'Content-Type' => 'text/plain'})
384
+ }.to raise_error(ArgumentError, /'post' requires a string 'body' argument/)
385
+ end
386
+
387
+ it 'raises an ArgumentError if `content_type` is missing from the headers hash' do
388
+ expect {
389
+ client.post(uri, "")
390
+ }.to raise_error(ArgumentError, /'post' requires a 'content-type' header/)
391
+ end
392
+
364
393
  context 'when connecting' do
365
394
  it 'uses a specified ssl context' do
366
395
  stub_request(:post, uri)
367
396
 
368
397
  other_context = Puppet::SSL::SSLContext.new
369
398
 
370
- client.post(uri, content_type: 'text/plain', body: "", ssl_context: other_context)
399
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {body: "", ssl_context: other_context})
371
400
  end
372
401
 
373
402
  it 'uses the system store' do
374
403
  stub_request(:post, uri)
375
404
 
376
- client.post(uri, content_type: 'text/plain', body: "", include_system_store: true)
405
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {include_system_store: true})
377
406
  end
378
407
 
379
408
  it 'raises an HTTPError if both are specified' do
380
409
  expect {
381
- client.post(uri, content_type: 'text/plain', body: "", ssl_context: puppet_context, include_system_store: true)
410
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {ssl_context: puppet_context, include_system_store: true})
382
411
  }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
383
412
  end
384
413
  end
@@ -424,18 +453,18 @@ describe Puppet::HTTP::Client do
424
453
 
425
454
  other_context = Puppet::SSL::SSLContext.new
426
455
 
427
- client.delete(uri, ssl_context: other_context)
456
+ client.delete(uri, options: {ssl_context: other_context})
428
457
  end
429
458
 
430
459
  it 'uses the system store' do
431
460
  stub_request(:delete, uri)
432
461
 
433
- client.delete(uri, include_system_store: true)
462
+ client.delete(uri, options: {include_system_store: true})
434
463
  end
435
464
 
436
465
  it 'raises an HTTPError if both are specified' do
437
466
  expect {
438
- client.delete(uri, ssl_context: puppet_context, include_system_store: true)
467
+ client.delete(uri, options: {ssl_context: puppet_context, include_system_store: true})
439
468
  }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
440
469
  end
441
470
  end
@@ -445,19 +474,19 @@ describe Puppet::HTTP::Client do
445
474
  it "submits credentials for GET requests" do
446
475
  stub_request(:get, uri).with(basic_auth: credentials)
447
476
 
448
- client.get(uri, user: 'user', password: 'pass')
477
+ client.get(uri, options: {user: 'user', password: 'pass'})
449
478
  end
450
479
 
451
480
  it "submits credentials for PUT requests" do
452
481
  stub_request(:put, uri).with(basic_auth: credentials)
453
482
 
454
- client.put(uri, content_type: 'text/plain', body: "hello", user: 'user', password: 'pass')
483
+ client.put(uri, "hello", headers: {'Content-Type' => 'text/plain'}, options: {user: 'user', password: 'pass'})
455
484
  end
456
485
 
457
486
  it "returns response containing access denied" do
458
487
  stub_request(:get, uri).with(basic_auth: credentials).to_return(status: [403, "Ye Shall Not Pass"])
459
488
 
460
- response = client.get(uri, user: 'user', password: 'pass')
489
+ response = client.get(uri, options: {user: 'user', password: 'pass'})
461
490
  expect(response.code).to eq(403)
462
491
  expect(response.reason).to eq("Ye Shall Not Pass")
463
492
  expect(response).to_not be_success
@@ -468,7 +497,7 @@ describe Puppet::HTTP::Client do
468
497
  expect(req.headers).to_not include('Authorization')
469
498
  end
470
499
 
471
- client.get(uri, user: nil, password: 'pass')
500
+ client.get(uri, options: {user: nil, password: 'pass'})
472
501
  end
473
502
 
474
503
  it 'omits basic auth if password is nil' do
@@ -476,7 +505,7 @@ describe Puppet::HTTP::Client do
476
505
  expect(req.headers).to_not include('Authorization')
477
506
  end
478
507
 
479
- client.get(uri, user: 'user', password: nil)
508
+ client.get(uri, options: {user: 'user', password: nil})
480
509
  end
481
510
  end
482
511
 
@@ -502,7 +531,7 @@ describe Puppet::HTTP::Client do
502
531
  stub_request(:put, start_url).to_return(redirect_to(url: bar_url))
503
532
  stub_request(:put, bar_url).to_return(status: 200)
504
533
 
505
- response = client.put(start_url, body: "", content_type: 'text/plain')
534
+ response = client.put(start_url, "", headers: {'Content-Type' => 'text/plain'})
506
535
  expect(response).to be_success
507
536
  end
508
537
 
@@ -528,7 +557,7 @@ describe Puppet::HTTP::Client do
528
557
  stub_request(:get, start_url).with(basic_auth: credentials).to_return(redirect_to(url: bar_url))
529
558
  stub_request(:get, bar_url).with(basic_auth: credentials).to_return(status: 200)
530
559
 
531
- client.get(start_url, user: 'user', password: 'pass')
560
+ client.get(start_url, options: {user: 'user', password: 'pass'})
532
561
  end
533
562
 
534
563
  it "redirects given a relative location" do
@@ -555,7 +584,7 @@ describe Puppet::HTTP::Client do
555
584
  stub_request(:put, start_url).with(body: data).to_return(redirect_to(url: bar_url))
556
585
  stub_request(:put, bar_url).with(body: data).to_return(status: 200)
557
586
 
558
- response = client.put(start_url, body: data, content_type: 'text/plain')
587
+ response = client.put(start_url, data, headers: {'Content-Type' => 'text/plain'})
559
588
  expect(response).to be_success
560
589
  end
561
590
 
@@ -698,7 +727,7 @@ describe Puppet::HTTP::Client do
698
727
  allow(http2).to receive(:started?).and_return(true)
699
728
 
700
729
 
701
- pool = Puppet::Network::HTTP::Pool.new()
730
+ pool = Puppet::Network::HTTP::Pool.new(15)
702
731
  client = Puppet::HTTP::Client.new(pool: pool)
703
732
 
704
733
  # The "with_connection" method is required to yield started connections
@@ -746,4 +775,34 @@ describe Puppet::HTTP::Client do
746
775
  client.get(uri)
747
776
  end
748
777
  end
778
+
779
+ context "persistent connections" do
780
+ before :each do
781
+ stub_request(:get, uri)
782
+ end
783
+
784
+ it 'defaults keepalive to http_keepalive_timeout' do
785
+ expect(client.pool.keepalive_timeout).to eq(Puppet[:http_keepalive_timeout])
786
+ end
787
+
788
+ it 'reuses a cached connection' do
789
+ allow(Puppet).to receive(:debug)
790
+ expect(Puppet).to receive(:debug).with(/^Creating new connection/)
791
+ expect(Puppet).to receive(:debug).with(/^Using cached connection/)
792
+
793
+ client.get(uri)
794
+ client.get(uri)
795
+ end
796
+
797
+ it 'can be disabled' do
798
+ Puppet[:http_keepalive_timeout] = 0
799
+
800
+ allow(Puppet).to receive(:debug)
801
+ expect(Puppet).to receive(:debug).with(/^Creating new connection/).twice
802
+ expect(Puppet).to receive(:debug).with(/^Using cached connection/).never
803
+
804
+ client.get(uri)
805
+ client.get(uri)
806
+ end
807
+ end
749
808
  end