puppet 6.12.0-x64-mingw32 → 6.17.0-x64-mingw32

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 (412) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +2 -7
  3. data/CONTRIBUTING.md +7 -13
  4. data/Gemfile +4 -2
  5. data/Gemfile.lock +39 -36
  6. data/README.md +18 -25
  7. data/ext/project_data.yaml +1 -1
  8. data/ext/windows/service/daemon.rb +3 -3
  9. data/lib/puppet.rb +52 -13
  10. data/lib/puppet/agent.rb +20 -14
  11. data/lib/puppet/application/agent.rb +26 -17
  12. data/lib/puppet/application/describe.rb +7 -5
  13. data/lib/puppet/application/device.rb +2 -2
  14. data/lib/puppet/application/filebucket.rb +19 -15
  15. data/lib/puppet/application/plugin.rb +1 -0
  16. data/lib/puppet/application/resource.rb +1 -1
  17. data/lib/puppet/application/ssl.rb +4 -4
  18. data/lib/puppet/configurer.rb +65 -69
  19. data/lib/puppet/configurer/plugin_handler.rb +10 -1
  20. data/lib/puppet/confine.rb +1 -1
  21. data/lib/puppet/context/trusted_information.rb +14 -8
  22. data/lib/puppet/daemon.rb +13 -27
  23. data/lib/puppet/defaults.rb +154 -58
  24. data/lib/puppet/environments.rb +27 -20
  25. data/lib/puppet/face/facts.rb +8 -5
  26. data/lib/puppet/face/help.rb +29 -3
  27. data/lib/puppet/face/module/search.rb +5 -0
  28. data/lib/puppet/face/plugin.rb +2 -2
  29. data/lib/puppet/file_serving/http_metadata.rb +14 -2
  30. data/lib/puppet/file_serving/metadata.rb +4 -1
  31. data/lib/puppet/file_serving/terminus_selector.rb +7 -8
  32. data/lib/puppet/file_system/file_impl.rb +14 -10
  33. data/lib/puppet/file_system/memory_file.rb +6 -0
  34. data/lib/puppet/file_system/memory_impl.rb +13 -0
  35. data/lib/puppet/file_system/uniquefile.rb +12 -16
  36. data/lib/puppet/file_system/windows.rb +7 -10
  37. data/lib/puppet/forge.rb +1 -1
  38. data/lib/puppet/forge/cache.rb +1 -1
  39. data/lib/puppet/forge/repository.rb +4 -7
  40. data/lib/puppet/functions/call.rb +1 -1
  41. data/lib/puppet/functions/eyaml_lookup_key.rb +13 -8
  42. data/lib/puppet/functions/filter.rb +1 -0
  43. data/lib/puppet/functions/reduce.rb +2 -4
  44. data/lib/puppet/http.rb +5 -0
  45. data/lib/puppet/http/client.rb +293 -73
  46. data/lib/puppet/http/errors.rb +2 -0
  47. data/lib/puppet/http/external_client.rb +90 -0
  48. data/lib/puppet/http/redirector.rb +43 -7
  49. data/lib/puppet/http/resolver.rb +46 -3
  50. data/lib/puppet/http/resolver/server_list.rb +76 -16
  51. data/lib/puppet/http/resolver/settings.rb +23 -3
  52. data/lib/puppet/http/resolver/srv.rb +29 -3
  53. data/lib/puppet/http/response.rb +87 -1
  54. data/lib/puppet/http/retry_after_handler.rb +39 -0
  55. data/lib/puppet/http/service.rb +151 -7
  56. data/lib/puppet/http/service/ca.rb +76 -14
  57. data/lib/puppet/http/service/compiler.rb +319 -0
  58. data/lib/puppet/http/service/file_server.rb +206 -0
  59. data/lib/puppet/http/service/report.rb +49 -23
  60. data/lib/puppet/http/session.rb +103 -7
  61. data/lib/puppet/indirector.rb +1 -1
  62. data/lib/puppet/indirector/catalog/compiler.rb +10 -0
  63. data/lib/puppet/indirector/catalog/rest.rb +34 -0
  64. data/lib/puppet/indirector/facts/rest.rb +42 -0
  65. data/lib/puppet/indirector/file_bucket_file/file.rb +1 -1
  66. data/lib/puppet/indirector/file_bucket_file/rest.rb +48 -0
  67. data/lib/puppet/indirector/file_content/http.rb +5 -0
  68. data/lib/puppet/indirector/file_content/rest.rb +30 -0
  69. data/lib/puppet/indirector/file_metadata/http.rb +27 -8
  70. data/lib/puppet/indirector/file_metadata/rest.rb +52 -0
  71. data/lib/puppet/indirector/json.rb +1 -1
  72. data/lib/puppet/indirector/msgpack.rb +1 -1
  73. data/lib/puppet/indirector/node/rest.rb +24 -0
  74. data/lib/puppet/indirector/report/rest.rb +19 -0
  75. data/lib/puppet/indirector/report/yaml.rb +23 -0
  76. data/lib/puppet/indirector/request.rb +1 -1
  77. data/lib/puppet/indirector/rest.rb +12 -0
  78. data/lib/puppet/indirector/status/rest.rb +18 -0
  79. data/lib/puppet/loaders.rb +6 -0
  80. data/lib/puppet/metatype/manager.rb +80 -80
  81. data/lib/puppet/network/http/api/indirected_routes.rb +1 -1
  82. data/lib/puppet/network/http/api/master/v3/environment.rb +3 -0
  83. data/lib/puppet/network/http/base_pool.rb +7 -2
  84. data/lib/puppet/network/http/compression.rb +7 -0
  85. data/lib/puppet/network/http/connection.rb +6 -0
  86. data/lib/puppet/network/http/connection_adapter.rb +184 -0
  87. data/lib/puppet/network/http/nocache_pool.rb +2 -0
  88. data/lib/puppet/network/http/pool.rb +13 -6
  89. data/lib/puppet/network/http_pool.rb +2 -1
  90. data/lib/puppet/node/environment.rb +11 -1
  91. data/lib/puppet/pal/catalog_compiler.rb +5 -0
  92. data/lib/puppet/pal/pal_impl.rb +4 -29
  93. data/lib/puppet/parser/ast/leaf.rb +5 -5
  94. data/lib/puppet/parser/ast/pops_bridge.rb +6 -15
  95. data/lib/puppet/parser/compiler.rb +43 -33
  96. data/lib/puppet/parser/compiler/catalog_validator/env_relationship_validator.rb +2 -0
  97. data/lib/puppet/parser/compiler/catalog_validator/site_validator.rb +2 -0
  98. data/lib/puppet/parser/environment_compiler.rb +4 -1
  99. data/lib/puppet/parser/functions.rb +18 -13
  100. data/lib/puppet/parser/functions/filter.rb +1 -0
  101. data/lib/puppet/parser/resource.rb +3 -2
  102. data/lib/puppet/parser/resource/param.rb +6 -0
  103. data/lib/puppet/pops/evaluator/access_operator.rb +2 -2
  104. data/lib/puppet/pops/evaluator/evaluator_impl.rb +6 -6
  105. data/lib/puppet/pops/issues.rb +5 -0
  106. data/lib/puppet/pops/loader/puppet_plan_instantiator.rb +12 -3
  107. data/lib/puppet/pops/loaders.rb +7 -5
  108. data/lib/puppet/pops/parser/evaluating_parser.rb +5 -7
  109. data/lib/puppet/pops/resource/resource_type_impl.rb +2 -0
  110. data/lib/puppet/pops/types/p_object_type_extension.rb +10 -0
  111. data/lib/puppet/pops/types/type_calculator.rb +24 -0
  112. data/lib/puppet/pops/validation/checker4_0.rb +11 -1
  113. data/lib/puppet/pops/validation/tasks_checker.rb +5 -1
  114. data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
  115. data/lib/puppet/provider/aix_object.rb +4 -2
  116. data/lib/puppet/provider/group/aix.rb +1 -0
  117. data/lib/puppet/provider/group/groupadd.rb +57 -24
  118. data/lib/puppet/provider/group/windows_adsi.rb +3 -3
  119. data/lib/puppet/provider/package/aix.rb +17 -2
  120. data/lib/puppet/provider/package/apt.rb +78 -4
  121. data/lib/puppet/provider/package/aptitude.rb +1 -1
  122. data/lib/puppet/provider/package/dnfmodule.rb +69 -15
  123. data/lib/puppet/provider/package/dpkg.rb +14 -7
  124. data/lib/puppet/provider/package/fink.rb +20 -3
  125. data/lib/puppet/provider/package/gem.rb +41 -7
  126. data/lib/puppet/provider/package/openbsd.rb +13 -1
  127. data/lib/puppet/provider/package/pacman.rb +2 -5
  128. data/lib/puppet/provider/package/pip.rb +143 -48
  129. data/lib/puppet/provider/package/pip3.rb +0 -2
  130. data/lib/puppet/provider/package/pkg.rb +18 -5
  131. data/lib/puppet/provider/package/pkgdmg.rb +1 -1
  132. data/lib/puppet/provider/package/pkgng.rb +16 -4
  133. data/lib/puppet/provider/package/portage.rb +2 -2
  134. data/lib/puppet/provider/package/puppet_gem.rb +6 -2
  135. data/lib/puppet/provider/package/rpm.rb +6 -213
  136. data/lib/puppet/provider/package/yum.rb +109 -25
  137. data/lib/puppet/provider/package/zypper.rb +59 -1
  138. data/lib/puppet/provider/service/systemd.rb +22 -4
  139. data/lib/puppet/provider/service/windows.rb +23 -7
  140. data/lib/puppet/provider/user/aix.rb +1 -0
  141. data/lib/puppet/provider/user/directoryservice.rb +30 -5
  142. data/lib/puppet/provider/user/useradd.rb +22 -12
  143. data/lib/puppet/reports/http.rb +15 -9
  144. data/lib/puppet/reports/store.rb +1 -1
  145. data/lib/puppet/resource.rb +2 -1
  146. data/lib/puppet/resource/type.rb +8 -0
  147. data/lib/puppet/resource/type_collection.rb +20 -16
  148. data/lib/puppet/runtime.rb +31 -1
  149. data/lib/puppet/settings.rb +4 -0
  150. data/lib/puppet/settings/http_extra_headers_setting.rb +25 -0
  151. data/lib/puppet/ssl.rb +1 -0
  152. data/lib/puppet/ssl/certificate.rb +2 -1
  153. data/lib/puppet/ssl/host.rb +4 -4
  154. data/lib/puppet/ssl/oids.rb +1 -0
  155. data/lib/puppet/ssl/ssl_context.rb +2 -2
  156. data/lib/puppet/ssl/ssl_provider.rb +20 -1
  157. data/lib/puppet/ssl/state_machine.rb +81 -35
  158. data/lib/puppet/ssl/verifier_adapter.rb +9 -1
  159. data/lib/puppet/test/test_helper.rb +15 -11
  160. data/lib/puppet/transaction/report.rb +2 -2
  161. data/lib/puppet/transaction/resource_harness.rb +1 -1
  162. data/lib/puppet/trusted_external.rb +29 -1
  163. data/lib/puppet/type.rb +18 -6
  164. data/lib/puppet/type/file.rb +51 -13
  165. data/lib/puppet/type/file/checksum.rb +4 -4
  166. data/lib/puppet/type/file/source.rb +51 -60
  167. data/lib/puppet/type/group.rb +2 -2
  168. data/lib/puppet/type/package.rb +102 -10
  169. data/lib/puppet/type/service.rb +55 -8
  170. data/lib/puppet/type/user.rb +3 -28
  171. data/lib/puppet/util.rb +39 -15
  172. data/lib/puppet/util/at_fork.rb +1 -1
  173. data/lib/puppet/util/autoload.rb +4 -18
  174. data/lib/puppet/util/checksums.rb +19 -4
  175. data/lib/puppet/util/fileparsing.rb +2 -2
  176. data/lib/puppet/util/instance_loader.rb +14 -10
  177. data/lib/puppet/util/log/destinations.rb +2 -11
  178. data/lib/puppet/util/package/version/debian.rb +175 -0
  179. data/lib/puppet/util/package/version/gem.rb +15 -0
  180. data/lib/puppet/util/package/version/pip.rb +167 -0
  181. data/lib/puppet/util/package/version/range.rb +53 -0
  182. data/lib/puppet/util/package/version/range/eq.rb +14 -0
  183. data/lib/puppet/util/package/version/range/gt.rb +14 -0
  184. data/lib/puppet/util/package/version/range/gt_eq.rb +14 -0
  185. data/lib/puppet/util/package/version/range/lt.rb +14 -0
  186. data/lib/puppet/util/package/version/range/lt_eq.rb +14 -0
  187. data/lib/puppet/util/package/version/range/min_max.rb +21 -0
  188. data/lib/puppet/util/package/version/range/simple.rb +11 -0
  189. data/lib/puppet/util/package/version/rpm.rb +73 -0
  190. data/lib/puppet/util/pidlock.rb +36 -10
  191. data/lib/puppet/util/platform.rb +5 -0
  192. data/lib/puppet/util/plist.rb +6 -0
  193. data/lib/puppet/util/provider_features.rb +1 -1
  194. data/lib/puppet/util/reference.rb +1 -1
  195. data/lib/puppet/util/rpm_compare.rb +193 -0
  196. data/lib/puppet/util/storage.rb +0 -1
  197. data/lib/puppet/util/windows/adsi.rb +2 -2
  198. data/lib/puppet/util/windows/api_types.rb +45 -32
  199. data/lib/puppet/util/windows/eventlog.rb +1 -6
  200. data/lib/puppet/util/windows/principal.rb +8 -6
  201. data/lib/puppet/util/windows/process.rb +15 -14
  202. data/lib/puppet/util/windows/registry.rb +11 -11
  203. data/lib/puppet/util/windows/security.rb +1 -0
  204. data/lib/puppet/util/windows/service.rb +43 -26
  205. data/lib/puppet/util/windows/sid.rb +3 -3
  206. data/lib/puppet/util/windows/user.rb +23 -8
  207. data/lib/puppet/util/yaml.rb +1 -1
  208. data/lib/puppet/version.rb +1 -1
  209. data/locales/puppet.pot +707 -574
  210. data/man/man5/puppet.conf.5 +74 -14
  211. data/man/man8/puppet-agent.8 +7 -7
  212. data/man/man8/puppet-apply.8 +1 -1
  213. data/man/man8/puppet-catalog.8 +1 -1
  214. data/man/man8/puppet-config.8 +1 -1
  215. data/man/man8/puppet-describe.8 +1 -1
  216. data/man/man8/puppet-device.8 +2 -2
  217. data/man/man8/puppet-doc.8 +1 -1
  218. data/man/man8/puppet-epp.8 +1 -1
  219. data/man/man8/puppet-facts.8 +1 -1
  220. data/man/man8/puppet-filebucket.8 +17 -2
  221. data/man/man8/puppet-generate.8 +1 -1
  222. data/man/man8/puppet-help.8 +6 -3
  223. data/man/man8/puppet-key.8 +1 -1
  224. data/man/man8/puppet-lookup.8 +1 -1
  225. data/man/man8/puppet-man.8 +1 -1
  226. data/man/man8/puppet-module.8 +4 -1
  227. data/man/man8/puppet-node.8 +1 -1
  228. data/man/man8/puppet-parser.8 +1 -1
  229. data/man/man8/puppet-plugin.8 +1 -1
  230. data/man/man8/puppet-report.8 +1 -1
  231. data/man/man8/puppet-resource.8 +1 -1
  232. data/man/man8/puppet-script.8 +1 -1
  233. data/man/man8/puppet-ssl.8 +2 -2
  234. data/man/man8/puppet-status.8 +1 -1
  235. data/man/man8/puppet.8 +2 -2
  236. data/spec/fixtures/ssl/unknown-127.0.0.1-key.pem +67 -0
  237. data/spec/fixtures/ssl/unknown-127.0.0.1.pem +48 -0
  238. data/spec/fixtures/ssl/unknown-ca-key.pem +67 -0
  239. data/spec/fixtures/ssl/unknown-ca.pem +59 -0
  240. data/spec/fixtures/unit/provider/package/dnfmodule/{dnf-module-list-installed.txt → dnf-module-list.txt} +8 -0
  241. data/spec/fixtures/unit/provider/package/pkgng/pkg.version +2 -0
  242. data/spec/fixtures/unit/provider/package/yum/yum-check-update-subscription-manager.txt +9 -0
  243. data/spec/fixtures/unit/provider/package/zypper/zypper-search-uninstalled.out +13 -0
  244. data/spec/fixtures/unit/provider/service/systemd/list_unit_files_services +9 -0
  245. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_fetch_if_not_on_the_local_disk.yml +1 -102
  246. 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 -106
  247. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_update_if_content_differs_on_disk.yml +1 -106
  248. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_mtime_is_older_on_disk.yml +1 -102
  249. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_no_header_specified.yml +1 -98
  250. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_not_on_the_local_disk.yml +1 -102
  251. 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 -102
  252. data/spec/integration/application/agent_spec.rb +483 -0
  253. data/spec/integration/application/apply_spec.rb +132 -3
  254. data/spec/integration/application/filebucket_spec.rb +190 -0
  255. data/spec/integration/application/plugin_spec.rb +73 -0
  256. data/spec/integration/configurer_spec.rb +26 -7
  257. data/spec/integration/defaults_spec.rb +1 -2
  258. data/spec/integration/http/client_spec.rb +47 -37
  259. data/spec/integration/indirector/facts/facter_spec.rb +4 -0
  260. data/spec/integration/indirector/report/yaml.rb +83 -0
  261. data/spec/integration/module_tool/forge_spec.rb +2 -15
  262. data/spec/integration/network/http_pool_spec.rb +93 -20
  263. data/spec/integration/node/environment_spec.rb +15 -0
  264. data/spec/integration/parser/compiler_spec.rb +11 -0
  265. data/spec/integration/type/file_spec.rb +1 -1
  266. data/spec/integration/util/windows/adsi_spec.rb +6 -1
  267. data/spec/integration/util/windows/registry_spec.rb +7 -7
  268. data/spec/integration/util/windows/user_spec.rb +40 -5
  269. data/spec/lib/puppet/test_ca.rb +2 -2
  270. data/spec/lib/puppet_spec/https.rb +16 -7
  271. data/spec/lib/puppet_spec/puppetserver.rb +119 -0
  272. data/spec/shared_contexts/https.rb +29 -0
  273. data/spec/unit/agent_spec.rb +80 -26
  274. data/spec/unit/application/agent_spec.rb +9 -5
  275. data/spec/unit/application/apply_spec.rb +2 -12
  276. data/spec/unit/application/describe_spec.rb +88 -50
  277. data/spec/unit/application/device_spec.rb +2 -2
  278. data/spec/unit/application/filebucket_spec.rb +22 -2
  279. data/spec/unit/application/resource_spec.rb +2 -2
  280. data/spec/unit/configurer/fact_handler_spec.rb +4 -8
  281. data/spec/unit/configurer/plugin_handler_spec.rb +36 -19
  282. data/spec/unit/configurer_spec.rb +17 -18
  283. data/spec/unit/context/trusted_information_spec.rb +25 -2
  284. data/spec/unit/daemon_spec.rb +5 -64
  285. data/spec/unit/defaults_spec.rb +25 -2
  286. data/spec/unit/environments_spec.rb +65 -28
  287. data/spec/unit/face/facts_spec.rb +24 -20
  288. data/spec/unit/face/module/search_spec.rb +17 -0
  289. data/spec/unit/face/plugin_spec.rb +12 -10
  290. data/spec/unit/file_serving/http_metadata_spec.rb +37 -14
  291. data/spec/unit/file_serving/terminus_selector_spec.rb +45 -26
  292. data/spec/unit/file_system/uniquefile_spec.rb +11 -0
  293. data/spec/unit/file_system_spec.rb +26 -2
  294. data/spec/unit/functions/lookup_spec.rb +13 -0
  295. data/spec/unit/http/client_spec.rb +327 -35
  296. data/spec/unit/http/external_client_spec.rb +201 -0
  297. data/spec/unit/http/resolver_spec.rb +34 -2
  298. data/spec/unit/http/response_spec.rb +75 -0
  299. data/spec/unit/http/service/ca_spec.rb +53 -11
  300. data/spec/unit/http/service/compiler_spec.rb +627 -0
  301. data/spec/unit/http/service/file_server_spec.rb +308 -0
  302. data/spec/unit/http/service/report_spec.rb +27 -9
  303. data/spec/unit/http/service_spec.rb +98 -5
  304. data/spec/unit/http/session_spec.rb +190 -7
  305. data/spec/unit/indirector/catalog/compiler_spec.rb +47 -29
  306. data/spec/unit/indirector/catalog/rest_spec.rb +59 -2
  307. data/spec/unit/indirector/facts/rest_spec.rb +79 -24
  308. data/spec/unit/indirector/file_bucket_file/rest_spec.rb +82 -2
  309. data/spec/unit/indirector/file_content/rest_spec.rb +53 -2
  310. data/spec/unit/indirector/file_metadata/http_spec.rb +194 -0
  311. data/spec/unit/indirector/file_metadata/rest_spec.rb +110 -2
  312. data/spec/unit/indirector/node/rest_spec.rb +57 -2
  313. data/spec/unit/indirector/report/rest_spec.rb +58 -51
  314. data/spec/unit/indirector/request_spec.rb +1 -1
  315. data/spec/unit/indirector/resource/ral_spec.rb +7 -8
  316. data/spec/unit/indirector/rest_spec.rb +13 -0
  317. data/spec/unit/indirector/status/rest_spec.rb +43 -2
  318. data/spec/unit/interface_spec.rb +3 -3
  319. data/spec/unit/network/http/api/indirected_routes_spec.rb +2 -1
  320. data/spec/unit/network/http/connection_spec.rb +559 -175
  321. data/spec/unit/network/http/nocache_pool_spec.rb +25 -3
  322. data/spec/unit/network/http/pool_spec.rb +89 -11
  323. data/spec/unit/network/http_pool_spec.rb +63 -57
  324. data/spec/unit/network/http_spec.rb +1 -1
  325. data/spec/unit/node/environment_spec.rb +16 -0
  326. data/spec/unit/node/facts_spec.rb +2 -1
  327. data/spec/unit/node_spec.rb +7 -4
  328. data/spec/unit/parser/ast/block_expression_spec.rb +1 -1
  329. data/spec/unit/parser/environment_compiler_spec.rb +7 -0
  330. data/spec/unit/parser/scope_spec.rb +1 -1
  331. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +15 -1
  332. data/spec/unit/pops/loaders/loaders_spec.rb +1 -1
  333. data/spec/unit/pops/serialization/to_from_hr_spec.rb +6 -1
  334. data/spec/unit/pops/types/type_calculator_spec.rb +1 -11
  335. data/spec/unit/pops/validator/validator_spec.rb +7 -2
  336. data/spec/unit/provider/aix_object_spec.rb +16 -2
  337. data/spec/unit/provider/group/groupadd_spec.rb +181 -56
  338. data/spec/unit/provider/group/windows_adsi_spec.rb +43 -10
  339. data/spec/unit/provider/package/aix_spec.rb +29 -0
  340. data/spec/unit/provider/package/apt_spec.rb +43 -2
  341. data/spec/unit/provider/package/aptitude_spec.rb +1 -0
  342. data/spec/unit/provider/package/dnfmodule_spec.rb +76 -15
  343. data/spec/unit/provider/package/dpkg_spec.rb +28 -6
  344. data/spec/unit/provider/package/gem_spec.rb +40 -0
  345. data/spec/unit/provider/package/openbsd_spec.rb +17 -0
  346. data/spec/unit/provider/package/pacman_spec.rb +6 -21
  347. data/spec/unit/provider/package/pip_spec.rb +68 -19
  348. data/spec/unit/provider/package/pkg_spec.rb +15 -1
  349. data/spec/unit/provider/package/pkgdmg_spec.rb +1 -1
  350. data/spec/unit/provider/package/pkgng_spec.rb +38 -0
  351. data/spec/unit/provider/package/portage_spec.rb +5 -0
  352. data/spec/unit/provider/package/puppet_gem_spec.rb +8 -0
  353. data/spec/unit/provider/package/rpm_spec.rb +0 -212
  354. data/spec/unit/provider/package/yum_spec.rb +292 -0
  355. data/spec/unit/provider/package/zypper_spec.rb +84 -0
  356. data/spec/unit/provider/service/init_spec.rb +1 -0
  357. data/spec/unit/provider/service/openbsd_spec.rb +9 -0
  358. data/spec/unit/provider/service/openwrt_spec.rb +1 -0
  359. data/spec/unit/provider/service/redhat_spec.rb +9 -0
  360. data/spec/unit/provider/service/systemd_spec.rb +92 -12
  361. data/spec/unit/provider/service/windows_spec.rb +22 -14
  362. data/spec/unit/provider/user/directoryservice_spec.rb +41 -0
  363. data/spec/unit/provider/user/openbsd_spec.rb +1 -0
  364. data/spec/unit/provider/user/useradd_spec.rb +43 -24
  365. data/spec/unit/provider/user/windows_adsi_spec.rb +3 -3
  366. data/spec/unit/puppet_pal_2pec.rb +0 -26
  367. data/spec/unit/puppet_pal_catalog_spec.rb +46 -0
  368. data/spec/unit/puppet_spec.rb +47 -0
  369. data/spec/unit/reports/http_spec.rb +70 -52
  370. data/spec/unit/resource_spec.rb +3 -3
  371. data/spec/unit/settings/autosign_setting_spec.rb +1 -1
  372. data/spec/unit/settings/http_extra_headers_spec.rb +64 -0
  373. data/spec/unit/ssl/certificate_spec.rb +7 -0
  374. data/spec/unit/ssl/host_spec.rb +4 -2
  375. data/spec/unit/ssl/oids_spec.rb +1 -0
  376. data/spec/unit/ssl/ssl_provider_spec.rb +69 -43
  377. data/spec/unit/ssl/state_machine_spec.rb +99 -13
  378. data/spec/unit/test/test_helper_spec.rb +17 -0
  379. data/spec/unit/transaction/persistence_spec.rb +1 -10
  380. data/spec/unit/transaction/report_spec.rb +5 -1
  381. data/spec/unit/transaction_spec.rb +0 -2
  382. data/spec/unit/type/file/ensure_spec.rb +1 -2
  383. data/spec/unit/type/file/source_spec.rb +89 -38
  384. data/spec/unit/type/file_spec.rb +122 -96
  385. data/spec/unit/type/package_spec.rb +8 -0
  386. data/spec/unit/type/service_spec.rb +185 -8
  387. data/spec/unit/type/user_spec.rb +1 -2
  388. data/spec/unit/type_spec.rb +50 -0
  389. data/spec/unit/util/at_fork_spec.rb +3 -2
  390. data/spec/unit/util/autoload_spec.rb +2 -1
  391. data/spec/unit/util/checksums_spec.rb +16 -0
  392. data/spec/unit/util/log/destinations_spec.rb +1 -29
  393. data/spec/unit/util/package/version/debian_spec.rb +83 -0
  394. data/spec/unit/util/package/version/pip_spec.rb +464 -0
  395. data/spec/unit/util/package/version/range_spec.rb +175 -0
  396. data/spec/unit/util/package/version/rpm_spec.rb +121 -0
  397. data/spec/unit/util/pidlock_spec.rb +112 -42
  398. data/spec/unit/util/plist_spec.rb +20 -0
  399. data/spec/unit/util/rpm_compare_spec.rb +196 -0
  400. data/spec/unit/util/storage_spec.rb +1 -8
  401. data/spec/unit/util/windows/adsi_spec.rb +4 -4
  402. data/spec/unit/util/windows/api_types_spec.rb +104 -40
  403. data/spec/unit/util/windows/service_spec.rb +4 -4
  404. data/spec/unit/util/windows/sid_spec.rb +2 -2
  405. data/spec/unit/util_spec.rb +3 -3
  406. data/spec/unit/x509/cert_provider_spec.rb +1 -1
  407. data/tasks/generate_cert_fixtures.rake +15 -1
  408. data/tasks/manpages.rake +5 -35
  409. metadata +73 -12
  410. data/COMMITTERS.md +0 -244
  411. data/spec/integration/faces/plugin_spec.rb +0 -61
  412. data/spec/integration/test/test_helper_spec.rb +0 -31
@@ -211,4 +211,21 @@ describe "puppet module search" do
211
211
  end
212
212
  end
213
213
  end
214
+
215
+ it "should include a deprecation warning" do
216
+ stub_request(:get, "https://forgeapi.puppet.com/v3/modules?query=puppetlabs-apache").to_return(status: 200, body: [answers: [], result: :success])
217
+
218
+ subject.search("puppetlabs-apache")
219
+
220
+ expect(@logs).to include(an_object_having_attributes(level: :warning, message: /This action has been deprecated. Please use the Puppet Forge to search for modules./))
221
+ end
222
+
223
+ it "omits the warning when deprecations are disabled" do
224
+ stub_request(:get, "https://forgeapi.puppet.com/v3/modules?query=puppetlabs-apache").to_return(status: 200, body: [answers: [], result: :success])
225
+
226
+ Puppet[:disable_warnings] = 'deprecations'
227
+ subject.search("puppetlabs-apache")
228
+
229
+ expect(@logs).not_to include(an_object_having_attributes(level: :warning))
230
+ end
214
231
  end
@@ -10,9 +10,10 @@ describe Puppet::Face[:plugin, :current] do
10
10
  end
11
11
 
12
12
  context "download" do
13
- before :each do
14
- #Server_agent version needs to be at 5.3.4 in order to mount locales
15
- Puppet.push_context({:server_agent_version => "5.3.4"})
13
+ around do |example|
14
+ Puppet.override(server_agent_version: "5.3.4") do
15
+ example.run
16
+ end
16
17
  end
17
18
 
18
19
  it "downloads plugins, external facts, and locales" do
@@ -61,9 +62,10 @@ describe Puppet::Face[:plugin, :current] do
61
62
  end
62
63
 
63
64
  context "download when server_agent_version is 5.3.3" do
64
- before :each do
65
- #Server_agent version needs to be at 5.3.4 in order to mount locales
66
- Puppet.push_context({:server_agent_version => "5.3.3"})
65
+ around do |example|
66
+ Puppet.override(server_agent_version: "5.3.3") do
67
+ example.run
68
+ end
67
69
  end
68
70
 
69
71
  it "downloads plugins, and external facts, but not locales" do
@@ -87,10 +89,10 @@ describe Puppet::Face[:plugin, :current] do
87
89
  end
88
90
 
89
91
  context "download when server_agent_version is blank" do
90
- before :each do
91
- #Server_agent version needs to be at 5.3.4 in order to mount locales
92
- #A blank version will default to 0.0
93
- Puppet.push_context({:server_agent_version => ""})
92
+ around do |example|
93
+ Puppet.override(server_agent_version: "") do
94
+ example.run
95
+ end
94
96
  end
95
97
 
96
98
  it "downloads plugins, and external facts, but not locales" do
@@ -30,11 +30,6 @@ describe Puppet::FileServing::HttpMetadata do
30
30
  end
31
31
 
32
32
  context "with no Last-Modified or Content-MD5 header from the server" do
33
- before do
34
- allow(http_response).to receive(:[]).with('last-modified').and_return(nil)
35
- allow(http_response).to receive(:[]).with('content-md5').and_return(nil)
36
- end
37
-
38
33
  it "should use :mtime as the checksum type, based on current time" do
39
34
  # Stringifying Time.now does some rounding; do so here so we don't end up with a time
40
35
  # that's greater than the stringified version returned by collect.
@@ -51,13 +46,9 @@ describe Puppet::FileServing::HttpMetadata do
51
46
  context "with a Last-Modified header from the server" do
52
47
  let(:time) { Time.now.utc }
53
48
 
54
- before do
55
- allow(http_response).to receive(:[]).with('content-md5').and_return(nil)
56
- end
57
-
58
49
  it "should use :mtime as the checksum type, based on Last-Modified" do
59
50
  # HTTP uses "GMT" not "UTC"
60
- allow(http_response).to receive(:[]).with('last-modified').and_return(time.strftime("%a, %d %b %Y %T GMT"))
51
+ http_response.add_field('last-modified', time.strftime("%a, %d %b %Y %T GMT"))
61
52
  metadata = described_class.new(http_response)
62
53
  metadata.collect
63
54
  expect( metadata.checksum_type ).to eq :mtime
@@ -70,16 +61,48 @@ describe Puppet::FileServing::HttpMetadata do
70
61
  let(:base64) { Digest::MD5.new.base64digest input }
71
62
  let(:hex) { Digest::MD5.new.hexdigest input }
72
63
 
73
- before do
74
- allow(http_response).to receive(:[]).with('last-modified').and_return(nil)
75
- allow(http_response).to receive(:[]).with('content-md5').and_return(base64)
64
+ it "should use the md5 checksum" do
65
+ http_response.add_field('content-md5', base64)
66
+ metadata = described_class.new(http_response)
67
+ metadata.collect
68
+ expect( metadata.checksum_type ).to eq :md5
69
+ expect( metadata.checksum ).to eq "{md5}#{hex}"
76
70
  end
71
+ end
72
+
73
+ context "with X-Checksum-Md5" do
74
+ let(:md5) { "c58989e9740a748de4f5054286faf99b" }
77
75
 
78
76
  it "should use the md5 checksum" do
77
+ http_response.add_field('X-Checksum-Md5', md5)
79
78
  metadata = described_class.new(http_response)
80
79
  metadata.collect
81
80
  expect( metadata.checksum_type ).to eq :md5
82
- expect( metadata.checksum ).to eq "{md5}#{hex}"
81
+ expect( metadata.checksum ).to eq "{md5}#{md5}"
82
+ end
83
+ end
84
+
85
+ context "with X-Checksum-Sha1" do
86
+ let(:sha1) { "01e4d15746f4274b84d740a93e04b9fd2882e3ea" }
87
+
88
+ it "should use the SHA1 checksum" do
89
+ http_response.add_field('X-Checksum-Sha1', sha1)
90
+ metadata = described_class.new(http_response)
91
+ metadata.collect
92
+ expect( metadata.checksum_type ).to eq :sha1
93
+ expect( metadata.checksum ).to eq "{sha1}#{sha1}"
94
+ end
95
+ end
96
+
97
+ context "with X-Checksum-Sha256" do
98
+ let(:sha256) { "a3eda98259c30e1e75039c2123670c18105e1c46efb672e42ca0e4cbe77b002a" }
99
+
100
+ it "should use the SHA256 checksum" do
101
+ http_response.add_field('X-Checksum-Sha256', sha256)
102
+ metadata = described_class.new(http_response)
103
+ metadata.collect
104
+ expect( metadata.checksum_type ).to eq :sha256
105
+ expect( metadata.checksum ).to eq "{sha256}#{sha256}"
83
106
  end
84
107
  end
85
108
  end
@@ -3,62 +3,81 @@ require 'spec_helper'
3
3
  require 'puppet/file_serving/terminus_selector'
4
4
 
5
5
  describe Puppet::FileServing::TerminusSelector do
6
- before do
7
- @object = Object.new
8
- @object.extend(Puppet::FileServing::TerminusSelector)
6
+ class TestSelector
7
+ include Puppet::FileServing::TerminusSelector
8
+ end
9
9
 
10
- @request = double('request', :key => "mymod/myfile", :options => {:node => "whatever"}, :server => nil, :protocol => nil)
10
+ def create_request(key)
11
+ Puppet::Indirector::Request.new(:indirection_name, :find, key, nil, {node: 'whatever'})
11
12
  end
12
13
 
14
+ subject { TestSelector.new }
15
+
13
16
  describe "when being used to select termini" do
14
17
  it "should return :file if the request key is fully qualified" do
15
- expect(@request).to receive(:key).and_return(File.expand_path('/foo'))
16
- expect(@object.select(@request)).to eq(:file)
18
+ request = create_request(File.expand_path('/foo'))
19
+
20
+ expect(subject.select(request)).to eq(:file)
21
+ end
22
+
23
+ it "should return :file_server if the request key is relative" do
24
+ request = create_request('modules/my_module/path/to_file')
25
+
26
+ expect(subject.select(request)).to eq(:file_server)
17
27
  end
18
28
 
19
29
  it "should return :file if the URI protocol is set to 'file'" do
20
- expect(@request).to receive(:protocol).and_return("file")
21
- expect(@object.select(@request)).to eq(:file)
30
+ request = create_request(Puppet::Util.path_to_uri(File.expand_path("/foo")).to_s)
31
+
32
+ expect(subject.select(request)).to eq(:file)
22
33
  end
23
34
 
24
35
  it "should return :http if the URI protocol is set to 'http'" do
25
- expect(@request).to receive(:protocol).and_return("http")
26
- expect(@object.select(@request)).to eq :http
36
+ request = create_request("http://www.example.com")
37
+
38
+ expect(subject.select(request)).to eq(:http)
27
39
  end
28
40
 
29
41
  it "should return :http if the URI protocol is set to 'https'" do
30
- expect(@request).to receive(:protocol).and_return("https")
31
- expect(@object.select(@request)).to eq :http
42
+ request = create_request("https://www.example.com")
43
+
44
+ expect(subject.select(request)).to eq(:http)
45
+ end
46
+
47
+ it "should return :http if the path starts with a double slash" do
48
+ request = create_request("https://www.example.com//index.html")
49
+
50
+ expect(subject.select(request)).to eq(:http)
32
51
  end
33
52
 
34
53
  it "should fail when a protocol other than :puppet, :http(s) or :file is used" do
35
- allow(@request).to receive(:protocol).and_return("ftp")
36
- expect { @object.select(@request) }.to raise_error(ArgumentError)
54
+ request = create_request("ftp://ftp.example.com")
55
+
56
+ expect {
57
+ subject.select(request)
58
+ }.to raise_error(ArgumentError, /URI protocol 'ftp' is not currently supported for file serving/)
37
59
  end
38
60
 
39
61
  describe "and the protocol is 'puppet'" do
40
- before do
41
- allow(@request).to receive(:protocol).and_return("puppet")
42
- end
43
-
44
62
  it "should choose :rest when a server is specified" do
45
- allow(@request).to receive(:protocol).and_return("puppet")
46
- expect(@request).to receive(:server).and_return("foo")
47
- expect(@object.select(@request)).to eq(:rest)
63
+ request = create_request("puppet://puppetserver.example.com")
64
+
65
+ expect(subject.select(request)).to eq(:rest)
48
66
  end
49
67
 
50
68
  # This is so a given file location works when bootstrapping with no server.
51
69
  it "should choose :rest when default_file_terminus is rest" do
52
- allow(@request).to receive(:protocol).and_return("puppet")
53
70
  Puppet[:server] = 'localhost'
54
- expect(@object.select(@request)).to eq(:rest)
71
+ request = create_request("puppet:///plugins")
72
+
73
+ expect(subject.select(request)).to eq(:rest)
55
74
  end
56
75
 
57
76
  it "should choose :file_server when default_file_terminus is file_server and no server is specified on the request" do
58
- expect(@request).to receive(:protocol).and_return("puppet")
59
- expect(@request).to receive(:server).and_return(nil)
60
77
  Puppet[:default_file_terminus] = 'file_server'
61
- expect(@object.select(@request)).to eq(:file_server)
78
+ request = create_request("puppet:///plugins")
79
+
80
+ expect(subject.select(request)).to eq(:file_server)
62
81
  end
63
82
  end
64
83
  end
@@ -1,6 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Puppet::FileSystem::Uniquefile do
4
+ include PuppetSpec::Files
5
+
4
6
  it "makes the name of the file available" do
5
7
  Puppet::FileSystem::Uniquefile.open_tmp('foo') do |file|
6
8
  expect(file.path).to match(/foo/)
@@ -73,6 +75,15 @@ describe Puppet::FileSystem::Uniquefile do
73
75
  Puppet::FileSystem::Uniquefile.open_tmp('foo') { |tmp| }
74
76
  end
75
77
 
78
+ it "reports when a parent directory does not exist" do
79
+ dir = tmpdir('uniquefile')
80
+ lock = File.join(dir, 'path', 'to', 'lock')
81
+
82
+ expect {
83
+ Puppet::FileSystem::Uniquefile.open_tmp(lock) { |tmp| }
84
+ }.to raise_error(Errno::ENOENT, %r{No such file or directory - A directory component in .* does not exist or is a dangling symbolic link})
85
+ end
86
+
76
87
  context "Ruby 1.9.3 Tempfile tests" do
77
88
  # the remaining tests in this file are ported directly from the ruby 1.9.3 source,
78
89
  # since most of this file was ported from there
@@ -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
@@ -988,7 +998,7 @@ describe "Puppet::FileSystem" do
988
998
  it 'rejects unsupported modes' do
989
999
  expect {
990
1000
  Puppet::FileSystem.replace_file(dest, 0755) { |_| }
991
- }.to raise_error(ArgumentError, /Only modes 0644, 0640 and 0600 are allowed/)
1001
+ }.to raise_error(ArgumentError, /Only modes 0644, 0640, 0660, and 0440 are allowed/)
992
1002
  end
993
1003
  end
994
1004
  end
@@ -1065,12 +1075,26 @@ describe "Puppet::FileSystem" do
1065
1075
  end
1066
1076
  end
1067
1077
 
1068
- it 'applies the specified mode' do
1078
+ it 'applies 0644 mode' do
1069
1079
  Puppet::FileSystem.replace_file(dest, 0644) { |f| f.write(content) }
1070
1080
 
1071
1081
  expects_public_file(dest)
1072
1082
  end
1073
1083
 
1084
+ [0660, 0640, 0600, 0440].each do |mode|
1085
+ it "applies #{mode} mode" do
1086
+ Puppet::FileSystem.replace_file(dest, mode) { |f| f.write(content) }
1087
+ current_sid = Puppet::Util::Windows::SID.name_to_sid(Puppet::Util::Windows::ADSI::User.current_user_name)
1088
+ sd = Puppet::Util::Windows::Security.get_security_descriptor(dest)
1089
+
1090
+ expect(sd.dacl).to contain_exactly(
1091
+ an_object_having_attributes(sid: Puppet::Util::Windows::SID::LocalSystem, mask: 0x1f01ff),
1092
+ an_object_having_attributes(sid: Puppet::Util::Windows::SID::BuiltinAdministrators, mask: 0x1f01ff),
1093
+ an_object_having_attributes(sid: current_sid, mask: 0x1f01ff),
1094
+ )
1095
+ end
1096
+ end
1097
+
1074
1098
  it 'raises Errno::EACCES if access is denied' do
1075
1099
  allow(Puppet::Util::Windows::Security).to receive(:get_security_descriptor).and_raise(Puppet::Util::Windows::Error.new('access denied', 5))
1076
1100
 
@@ -3082,6 +3082,19 @@ describe "The lookup function" do
3082
3082
 
3083
3083
  let(:env_data) { data_files }
3084
3084
 
3085
+ context 'with unencryptable eyaml' do
3086
+ let(:data_files) do
3087
+ {
3088
+ 'common.eyaml' => <<-YAML.unindent
3089
+ key_with_invalid_eyaml: ENC[PKCS7,INVALID]
3090
+ YAML
3091
+ }
3092
+ end
3093
+
3094
+ it 'fails and reports error with ENC value, key being looked up and filename' do
3095
+ expect { lookup('key_with_invalid_eyaml') }.to raise_error(Puppet::DataBinding::LookupError, /hiera-eyaml backend error decrypting ENC\[PKCS7,INVALID\] when looking up key_with_invalid_eyaml in .*common\.eyaml\. Error was/)
3096
+ end
3097
+ end
3085
3098
  context 'and a module using eyaml with different options' do
3086
3099
 
3087
3100
  let(:private_module_key) do
@@ -4,7 +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(:client) { described_class.new }
7
+ let(:puppet_context) { Puppet::SSL::SSLContext.new }
8
+ let(:system_context) { Puppet::SSL::SSLContext.new }
9
+ let(:client) { described_class.new(ssl_context: puppet_context, system_ssl_context: system_context) }
8
10
  let(:credentials) { ['user', 'pass'] }
9
11
 
10
12
  it 'creates unique sessions' do
@@ -45,6 +47,46 @@ describe Puppet::HTTP::Client do
45
47
  client.connect(uri)
46
48
  }.to raise_error(Puppet::HTTP::ConnectionError, %r{^Request to https://www.example.com timed out connect operation after .* seconds})
47
49
  end
50
+
51
+ it 'connects using the default ssl context' do
52
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
53
+ expect(verifier.ssl_context).to equal(puppet_context)
54
+ end
55
+
56
+ client.connect(uri)
57
+ end
58
+
59
+ it 'connects using a specified ssl context' do
60
+ other_context = Puppet::SSL::SSLContext.new
61
+
62
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
63
+ expect(verifier.ssl_context).to equal(other_context)
64
+ end
65
+
66
+ client.connect(uri, options: {ssl_context: other_context})
67
+ end
68
+
69
+ it 'connects using the system store' do
70
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
71
+ expect(verifier.ssl_context).to equal(system_context)
72
+ end
73
+
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'))
83
+ end
84
+
85
+ it 'raises an HTTPError if both are specified' do
86
+ expect {
87
+ client.connect(uri, options: {ssl_context: puppet_context, include_system_store: true})
88
+ }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
89
+ end
48
90
  end
49
91
 
50
92
  context 'after connecting' do
@@ -75,10 +117,8 @@ describe Puppet::HTTP::Client do
75
117
 
76
118
  context "when closing" do
77
119
  it "closes all connections in the pool" do
78
- pool = double('pool')
79
- expect(pool).to receive(:close)
120
+ expect(client.pool).to receive(:close)
80
121
 
81
- client = described_class.new(pool: pool)
82
122
  client.close
83
123
  end
84
124
  end
@@ -99,6 +139,12 @@ describe Puppet::HTTP::Client do
99
139
  client.get(uri, params: {:foo => "bar=baz"})
100
140
  end
101
141
 
142
+ it "fails if a user passes in an invalid param type" do
143
+ environment = Puppet::Node::Environment.create(:testing, [])
144
+
145
+ expect{client.get(uri, params: {environment: environment})}.to raise_error(Puppet::HTTP::SerializationError, /HTTP REST queries cannot handle values of type/)
146
+ end
147
+
102
148
  it "merges custom headers with default ones" do
103
149
  stub_request(:get, uri).with(headers: { 'X-Foo' => 'Bar', 'X-Puppet-Version' => /./, 'User-Agent' => /./ })
104
150
 
@@ -132,6 +178,28 @@ describe Puppet::HTTP::Client do
132
178
 
133
179
  expect(io.string).to eq("abc")
134
180
  end
181
+
182
+ context 'when connecting' do
183
+ it 'uses a specified ssl context' do
184
+ stub_request(:get, uri).to_return(body: "abc")
185
+
186
+ other_context = Puppet::SSL::SSLContext.new
187
+
188
+ client.get(uri, options: {ssl_context: other_context})
189
+ end
190
+
191
+ it 'uses the system store' do
192
+ stub_request(:get, uri).to_return(body: "abc")
193
+
194
+ client.get(uri, options: {include_system_store: true})
195
+ end
196
+
197
+ it 'raises an HTTPError if both are specified' do
198
+ expect {
199
+ client.get(uri, options: {ssl_context: puppet_context, include_system_store: true})
200
+ }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
201
+ end
202
+ end
135
203
  end
136
204
 
137
205
  context "for HEAD requests" do
@@ -167,6 +235,28 @@ describe Puppet::HTTP::Client do
167
235
 
168
236
  expect(client.head(uri).body).to eq("abc")
169
237
  end
238
+
239
+ context 'when connecting' do
240
+ it 'uses a specified ssl context' do
241
+ stub_request(:head, uri)
242
+
243
+ other_context = Puppet::SSL::SSLContext.new
244
+
245
+ client.head(uri, options: {ssl_context: other_context})
246
+ end
247
+
248
+ it 'uses the system store' do
249
+ stub_request(:head, uri)
250
+
251
+ client.head(uri, options: {include_system_store: true})
252
+ end
253
+
254
+ it 'raises an HTTPError if both are specified' do
255
+ expect {
256
+ client.head(uri, options: {ssl_context: puppet_context, include_system_store: true})
257
+ }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
258
+ end
259
+ end
170
260
  end
171
261
 
172
262
  context "for PUT requests" do
@@ -176,25 +266,25 @@ describe Puppet::HTTP::Client do
176
266
  expect(request.headers).to_not include('X-Puppet-Profiling')
177
267
  end
178
268
 
179
- client.put(uri, content_type: 'text/plain', body: "")
269
+ client.put(uri, "", headers: {'Content-Type' => 'text/plain'})
180
270
  end
181
271
 
182
272
  it "stringifies keys and encodes values in the query" do
183
273
  stub_request(:put, "https://www.example.com").with(query: "foo=bar%3Dbaz")
184
274
 
185
- 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'})
186
276
  end
187
277
 
188
278
  it "includes custom headers" do
189
279
  stub_request(:put, "https://www.example.com").with(headers: { 'X-Foo' => 'Bar' })
190
280
 
191
- client.put(uri, headers: {'X-Foo' => 'Bar'}, content_type: 'text/plain', body: "")
281
+ client.put(uri, "", headers: {'X-Foo' => 'Bar', 'Content-Type' => 'text/plain'})
192
282
  end
193
283
 
194
284
  it "returns the response" do
195
285
  stub_request(:put, uri)
196
286
 
197
- response = client.put(uri, content_type: 'text/plain', body: "")
287
+ response = client.put(uri, "", headers: {'Content-Type' => 'text/plain'})
198
288
  expect(response).to be_an_instance_of(Puppet::HTTP::Response)
199
289
  expect(response).to be_success
200
290
  expect(response.code).to eq(200)
@@ -203,7 +293,41 @@ describe Puppet::HTTP::Client do
203
293
  it "sets content-length and content-type for the body" do
204
294
  stub_request(:put, uri).with(headers: {"Content-Length" => "5", "Content-Type" => "text/plain"})
205
295
 
206
- client.put(uri, content_type: 'text/plain', body: "hello")
296
+ client.put(uri, "hello", headers: {'Content-Type' => 'text/plain'})
297
+ end
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
+
311
+ context 'when connecting' do
312
+ it 'uses a specified ssl context' do
313
+ stub_request(:put, uri)
314
+
315
+ other_context = Puppet::SSL::SSLContext.new
316
+
317
+ client.put(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {ssl_context: other_context})
318
+ end
319
+
320
+ it 'uses the system store' do
321
+ stub_request(:put, uri)
322
+
323
+ client.put(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {include_system_store: true})
324
+ end
325
+
326
+ it 'raises an HTTPError if both are specified' do
327
+ expect {
328
+ client.put(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {ssl_context: puppet_context, include_system_store: true})
329
+ }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
330
+ end
207
331
  end
208
332
  end
209
333
 
@@ -211,25 +335,25 @@ describe Puppet::HTTP::Client do
211
335
  it "includes default HTTP headers" do
212
336
  stub_request(:post, uri).with(headers: {'X-Puppet-Version' => /./, 'User-Agent' => /./})
213
337
 
214
- client.post(uri, content_type: 'text/plain', body: "")
338
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'})
215
339
  end
216
340
 
217
341
  it "stringifies keys and encodes values in the query" do
218
342
  stub_request(:post, "https://www.example.com").with(query: "foo=bar%3Dbaz")
219
343
 
220
- 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'})
221
345
  end
222
346
 
223
347
  it "includes custom headers" do
224
348
  stub_request(:post, "https://www.example.com").with(headers: { 'X-Foo' => 'Bar' })
225
349
 
226
- client.post(uri, headers: {'X-Foo' => 'Bar'}, content_type: 'text/plain', body: "")
350
+ client.post(uri, "", headers: {'X-Foo' => 'Bar', 'Content-Type' => 'text/plain'})
227
351
  end
228
352
 
229
353
  it "returns the response" do
230
354
  stub_request(:post, uri)
231
355
 
232
- response = client.post(uri, content_type: 'text/plain', body: "")
356
+ response = client.post(uri, "", headers: {'Content-Type' => 'text/plain'})
233
357
  expect(response).to be_an_instance_of(Puppet::HTTP::Response)
234
358
  expect(response).to be_success
235
359
  expect(response.code).to eq(200)
@@ -238,14 +362,14 @@ describe Puppet::HTTP::Client do
238
362
  it "sets content-length and content-type for the body" do
239
363
  stub_request(:post, uri).with(headers: {"Content-Length" => "5", "Content-Type" => "text/plain"})
240
364
 
241
- client.post(uri, content_type: 'text/plain', body: "hello")
365
+ client.post(uri, "hello", headers: {'Content-Type' => 'text/plain'})
242
366
  end
243
367
 
244
368
  it "streams the response body when a block is given" do
245
369
  stub_request(:post, uri).to_return(body: "abc")
246
370
 
247
371
  io = StringIO.new
248
- client.post(uri, content_type: 'text/plain', body: "") do |response|
372
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}) do |response|
249
373
  response.read_body do |data|
250
374
  io.write(data)
251
375
  end
@@ -253,6 +377,40 @@ describe Puppet::HTTP::Client do
253
377
 
254
378
  expect(io.string).to eq("abc")
255
379
  end
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
+
393
+ context 'when connecting' do
394
+ it 'uses a specified ssl context' do
395
+ stub_request(:post, uri)
396
+
397
+ other_context = Puppet::SSL::SSLContext.new
398
+
399
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {body: "", ssl_context: other_context})
400
+ end
401
+
402
+ it 'uses the system store' do
403
+ stub_request(:post, uri)
404
+
405
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {include_system_store: true})
406
+ end
407
+
408
+ it 'raises an HTTPError if both are specified' do
409
+ expect {
410
+ client.post(uri, "", headers: {'Content-Type' => 'text/plain'}, options: {ssl_context: puppet_context, include_system_store: true})
411
+ }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
412
+ end
413
+ end
256
414
  end
257
415
 
258
416
  context "for DELETE requests" do
@@ -288,44 +446,80 @@ describe Puppet::HTTP::Client do
288
446
 
289
447
  expect(client.delete(uri).body).to eq("abc")
290
448
  end
449
+
450
+ context 'when connecting' do
451
+ it 'uses a specified ssl context' do
452
+ stub_request(:delete, uri)
453
+
454
+ other_context = Puppet::SSL::SSLContext.new
455
+
456
+ client.delete(uri, options: {ssl_context: other_context})
457
+ end
458
+
459
+ it 'uses the system store' do
460
+ stub_request(:delete, uri)
461
+
462
+ client.delete(uri, options: {include_system_store: true})
463
+ end
464
+
465
+ it 'raises an HTTPError if both are specified' do
466
+ expect {
467
+ client.delete(uri, options: {ssl_context: puppet_context, include_system_store: true})
468
+ }.to raise_error(Puppet::HTTP::HTTPError, /The ssl_context and include_system_store parameters are mutually exclusive/)
469
+ end
470
+ end
291
471
  end
292
472
 
293
473
  context "Basic Auth" do
294
474
  it "submits credentials for GET requests" do
295
475
  stub_request(:get, uri).with(basic_auth: credentials)
296
476
 
297
- client.get(uri, user: 'user', password: 'pass')
477
+ client.get(uri, options: {basic_auth: {user: 'user', password: 'pass'}})
298
478
  end
299
479
 
300
480
  it "submits credentials for PUT requests" do
301
481
  stub_request(:put, uri).with(basic_auth: credentials)
302
482
 
303
- client.put(uri, content_type: 'text/plain', body: "hello", user: 'user', password: 'pass')
483
+ client.put(uri, "hello", headers: {'Content-Type' => 'text/plain'}, options: {basic_auth: {user: 'user', password: 'pass'}})
304
484
  end
305
485
 
306
486
  it "returns response containing access denied" do
307
487
  stub_request(:get, uri).with(basic_auth: credentials).to_return(status: [403, "Ye Shall Not Pass"])
308
488
 
309
- response = client.get(uri, user: 'user', password: 'pass')
489
+ response = client.get(uri, options: {basic_auth: {user: 'user', password: 'pass'}})
310
490
  expect(response.code).to eq(403)
311
491
  expect(response.reason).to eq("Ye Shall Not Pass")
312
492
  expect(response).to_not be_success
313
493
  end
314
494
 
315
- it 'omits basic auth if user is nil' do
495
+ it 'includes basic auth if user is nil' do
316
496
  stub_request(:get, uri).with do |req|
317
- expect(req.headers).to_not include('Authorization')
497
+ expect(req.headers).to include('Authorization')
318
498
  end
319
499
 
320
- client.get(uri, user: nil, password: 'pass')
500
+ client.get(uri, options: {basic_auth: {user: nil, password: 'pass'}})
321
501
  end
322
502
 
323
- it 'omits basic auth if password is nil' do
503
+ it 'includes basic auth if password is nil' do
324
504
  stub_request(:get, uri).with do |req|
325
- expect(req.headers).to_not include('Authorization')
505
+ expect(req.headers).to include('Authorization')
326
506
  end
327
507
 
328
- client.get(uri, user: 'user', password: nil)
508
+ client.get(uri, options: {basic_auth: {user: 'user', password: nil}})
509
+ end
510
+
511
+ it 'observes userinfo in the URL' do
512
+ stub_request(:get, uri).with(basic_auth: credentials)
513
+
514
+ client.get(URI("https://user:pass@www.example.com"))
515
+ end
516
+
517
+ it 'prefers explicit basic_auth credentials' do
518
+ uri = URI("https://ignored_user:ignored_pass@www.example.com")
519
+
520
+ stub_request(:get, "https://www.example.com").with(basic_auth: credentials)
521
+
522
+ client.get(uri, options: {basic_auth: {user: 'user', password: 'pass'}})
329
523
  end
330
524
  end
331
525
 
@@ -351,14 +545,45 @@ describe Puppet::HTTP::Client do
351
545
  stub_request(:put, start_url).to_return(redirect_to(url: bar_url))
352
546
  stub_request(:put, bar_url).to_return(status: 200)
353
547
 
354
- response = client.put(start_url, body: "", content_type: 'text/plain')
548
+ response = client.put(start_url, "", headers: {'Content-Type' => 'text/plain'})
549
+ expect(response).to be_success
550
+ end
551
+
552
+ it "updates the Host header from the Location host and port" do
553
+ stub_request(:get, start_url).with(headers: { 'Host' => 'www.example.com:8140' })
554
+ .to_return(redirect_to(url: other_host))
555
+ stub_request(:get, other_host).with(headers: { 'Host' => 'other.example.com:8140' })
556
+ .to_return(status: 200)
557
+
558
+ response = client.get(start_url)
559
+ expect(response).to be_success
560
+ end
561
+
562
+ it "omits the default HTTPS port from the Host header" do
563
+ stub_request(:get, start_url).with(headers: { 'Host' => 'www.example.com:8140' })
564
+ .to_return(redirect_to(url: "https://other.example.com/qux"))
565
+ stub_request(:get, "https://other.example.com/qux").with(headers: { 'Host' => 'other.example.com' })
566
+ .to_return(status: 200)
567
+
568
+ response = client.get(start_url)
569
+ expect(response).to be_success
570
+ end
571
+
572
+ it "omits the default HTTP port from the Host header" do
573
+ stub_request(:get, start_url).with(headers: { 'Host' => 'www.example.com:8140' })
574
+ .to_return(redirect_to(url: "http://other.example.com/qux"))
575
+ stub_request(:get, "http://other.example.com/qux").with(headers: { 'Host' => 'other.example.com' })
576
+ .to_return(status: 200)
577
+
578
+ response = client.get(start_url)
355
579
  expect(response).to be_success
356
580
  end
357
581
 
358
- it "preserves query parameters" do
359
- query = { 'debug' => true }
360
- stub_request(:get, start_url).with(query: query).to_return(redirect_to(url: bar_url))
361
- stub_request(:get, bar_url).with(query: query).to_return(status: 200)
582
+ it "applies query parameters from the location header" do
583
+ query = { 'redirected' => false }
584
+
585
+ stub_request(:get, start_url).with(query: query).to_return(redirect_to(url: "#{bar_url}?redirected=true"))
586
+ stub_request(:get, bar_url).with(query: {'redirected' => 'true'}).to_return(status: 200)
362
587
 
363
588
  response = client.get(start_url, params: query)
364
589
  expect(response).to be_success
@@ -377,7 +602,7 @@ describe Puppet::HTTP::Client do
377
602
  stub_request(:get, start_url).with(basic_auth: credentials).to_return(redirect_to(url: bar_url))
378
603
  stub_request(:get, bar_url).with(basic_auth: credentials).to_return(status: 200)
379
604
 
380
- client.get(start_url, user: 'user', password: 'pass')
605
+ client.get(start_url, options: {basic_auth: {user: 'user', password: 'pass'}})
381
606
  end
382
607
 
383
608
  it "redirects given a relative location" do
@@ -389,22 +614,33 @@ describe Puppet::HTTP::Client do
389
614
  expect(response).to be_success
390
615
  end
391
616
 
392
- it "preserves query parameters given a relative location" do
617
+ it "applies query parameters from the location header" do
393
618
  relative_url = "/people.html"
394
- query = { 'debug' => true }
395
- stub_request(:get, start_url).with(query: query).to_return(redirect_to(url: relative_url))
396
- stub_request(:get, "https://www.example.com:8140/people.html").with(query: query).to_return(status: 200)
619
+ query = { 'redirected' => false }
620
+ stub_request(:get, start_url).with(query: query).to_return(redirect_to(url: "#{relative_url}?redirected=true"))
621
+ stub_request(:get, "https://www.example.com:8140/people.html").with(query: {'redirected' => 'true'}).to_return(status: 200)
397
622
 
398
623
  response = client.get(start_url, params: query)
399
624
  expect(response).to be_success
400
625
  end
401
626
 
627
+ it "removes dot segments from a relative location" do
628
+ # from https://tools.ietf.org/html/rfc3986#section-5.4.2
629
+ base_url = URI("http://a/b/c/d;p?q")
630
+ relative_url = "../../../../g"
631
+ stub_request(:get, base_url).to_return(redirect_to(url: relative_url))
632
+ stub_request(:get, "http://a/g").to_return(status: 200)
633
+
634
+ response = client.get(base_url)
635
+ expect(response).to be_success
636
+ end
637
+
402
638
  it "preserves request body for each request" do
403
639
  data = 'some data'
404
640
  stub_request(:put, start_url).with(body: data).to_return(redirect_to(url: bar_url))
405
641
  stub_request(:put, bar_url).with(body: data).to_return(status: 200)
406
642
 
407
- response = client.put(start_url, body: data, content_type: 'text/plain')
643
+ response = client.put(start_url, data, headers: {'Content-Type' => 'text/plain'})
408
644
  expect(response).to be_success
409
645
  end
410
646
 
@@ -533,6 +769,32 @@ describe Puppet::HTTP::Client do
533
769
  }.to raise_error(Puppet::HTTP::ProtocolError, /Failed to parse Retry-After header 'foo' as an integer or RFC 2822 date/)
534
770
  end
535
771
 
772
+ it "should close the connection before sleeping" do
773
+ retry_after('42')
774
+
775
+ site = Puppet::Network::HTTP::Site.from_uri(uri)
776
+
777
+ http1 = Net::HTTP.new(site.host, site.port)
778
+ http1.use_ssl = true
779
+ allow(http1).to receive(:started?).and_return(true)
780
+
781
+ http2 = Net::HTTP.new(site.host, site.port)
782
+ http2.use_ssl = true
783
+ allow(http2).to receive(:started?).and_return(true)
784
+
785
+
786
+ pool = Puppet::Network::HTTP::Pool.new(15)
787
+ client = Puppet::HTTP::Client.new(pool: pool)
788
+
789
+ # The "with_connection" method is required to yield started connections
790
+ allow(pool).to receive(:with_connection).and_yield(http1).and_yield(http2)
791
+
792
+ expect(http1).to receive(:finish).ordered
793
+ expect(::Kernel).to receive(:sleep).with(42).ordered
794
+
795
+ client.get(uri)
796
+ end
797
+
536
798
  it "should sleep and retry if Retry-After is an Integer" do
537
799
  retry_after('42')
538
800
 
@@ -569,4 +831,34 @@ describe Puppet::HTTP::Client do
569
831
  client.get(uri)
570
832
  end
571
833
  end
834
+
835
+ context "persistent connections" do
836
+ before :each do
837
+ stub_request(:get, uri)
838
+ end
839
+
840
+ it 'defaults keepalive to http_keepalive_timeout' do
841
+ expect(client.pool.keepalive_timeout).to eq(Puppet[:http_keepalive_timeout])
842
+ end
843
+
844
+ it 'reuses a cached connection' do
845
+ allow(Puppet).to receive(:debug)
846
+ expect(Puppet).to receive(:debug).with(/^Creating new connection/)
847
+ expect(Puppet).to receive(:debug).with(/^Using cached connection/)
848
+
849
+ client.get(uri)
850
+ client.get(uri)
851
+ end
852
+
853
+ it 'can be disabled' do
854
+ Puppet[:http_keepalive_timeout] = 0
855
+
856
+ allow(Puppet).to receive(:debug)
857
+ expect(Puppet).to receive(:debug).with(/^Creating new connection/).twice
858
+ expect(Puppet).to receive(:debug).with(/^Using cached connection/).never
859
+
860
+ client.get(uri)
861
+ client.get(uri)
862
+ end
863
+ end
572
864
  end