puppet 5.3.7-universal-darwin → 5.4.0-universal-darwin

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 (454) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +42 -29
  3. data/README.md +8 -6
  4. data/ext/cert_inspector +2 -2
  5. data/ext/envpuppet +1 -1
  6. data/ext/gentoo/init.d/puppetmaster +4 -4
  7. data/ext/ips/puppet-agent +11 -11
  8. data/ext/ips/puppet-master +11 -11
  9. data/ext/puppet-test +1 -2
  10. data/ext/redhat/client.init +2 -2
  11. data/ext/redhat/logrotate +1 -1
  12. data/ext/solaris/smf/puppet +11 -11
  13. data/ext/solaris/smf/svc-puppetd +5 -5
  14. data/ext/solaris/smf/svc-puppetmasterd +5 -5
  15. data/ext/windows/service/daemon.rb +1 -1
  16. data/install.rb +2 -3
  17. data/lib/puppet/agent.rb +1 -1
  18. data/lib/puppet/application/cert.rb +1 -3
  19. data/lib/puppet/application/describe.rb +0 -1
  20. data/lib/puppet/application/device.rb +12 -99
  21. data/lib/puppet/application/filebucket.rb +32 -11
  22. data/lib/puppet/application/lookup.rb +1 -11
  23. data/lib/puppet/application/script.rb +261 -0
  24. data/lib/puppet/configurer.rb +3 -4
  25. data/lib/puppet/configurer/plugin_handler.rb +26 -9
  26. data/lib/puppet/context.rb +1 -1
  27. data/lib/puppet/datatypes.rb +213 -0
  28. data/lib/puppet/datatypes/error.rb +21 -0
  29. data/lib/puppet/datatypes/impl/error.rb +40 -0
  30. data/lib/puppet/defaults.rb +51 -20
  31. data/lib/puppet/environments.rb +17 -0
  32. data/lib/puppet/error.rb +17 -0
  33. data/lib/puppet/etc.rb +2 -2
  34. data/lib/puppet/external/pson/pure/generator.rb +1 -1
  35. data/lib/puppet/external/pson/pure/parser.rb +1 -1
  36. data/lib/puppet/face/config.rb +45 -0
  37. data/lib/puppet/face/epp.rb +3 -3
  38. data/lib/puppet/face/help/action.erb +3 -0
  39. data/lib/puppet/face/module/build.rb +1 -0
  40. data/lib/puppet/face/module/generate.rb +5 -0
  41. data/lib/puppet/face/module/install.rb +1 -0
  42. data/lib/puppet/face/module/search.rb +6 -2
  43. data/lib/puppet/face/module/uninstall.rb +1 -0
  44. data/lib/puppet/face/module/upgrade.rb +1 -0
  45. data/lib/puppet/face/parser.rb +0 -1
  46. data/lib/puppet/face/plugin.rb +1 -3
  47. data/lib/puppet/feature/base.rb +1 -1
  48. data/lib/puppet/feature/bolt.rb +3 -0
  49. data/lib/puppet/file_bucket/dipper.rb +1 -2
  50. data/lib/puppet/file_serving/http_metadata.rb +1 -1
  51. data/lib/puppet/file_system/uniquefile.rb +2 -2
  52. data/lib/puppet/forge.rb +6 -0
  53. data/lib/puppet/functions.rb +70 -88
  54. data/lib/puppet/functions/all.rb +6 -2
  55. data/lib/puppet/functions/annotate.rb +1 -1
  56. data/lib/puppet/functions/any.rb +7 -3
  57. data/lib/puppet/functions/contain.rb +6 -0
  58. data/lib/puppet/functions/convert_to.rb +32 -0
  59. data/lib/puppet/functions/defined.rb +0 -3
  60. data/lib/puppet/functions/each.rb +10 -6
  61. data/lib/puppet/functions/filter.rb +16 -10
  62. data/lib/puppet/functions/find_file.rb +0 -1
  63. data/lib/puppet/functions/include.rb +6 -0
  64. data/lib/puppet/functions/map.rb +12 -9
  65. data/lib/puppet/functions/module_directory.rb +41 -0
  66. data/lib/puppet/functions/new.rb +1 -4
  67. data/lib/puppet/functions/regsubst.rb +1 -1
  68. data/lib/puppet/functions/require.rb +6 -0
  69. data/lib/puppet/generate/type.rb +1 -1
  70. data/lib/puppet/gettext/config.rb +2 -2
  71. data/lib/puppet/gettext/stubs.rb +1 -1
  72. data/lib/puppet/indirector/catalog/compiler.rb +0 -1
  73. data/lib/puppet/indirector/file_bucket_file/file.rb +6 -2
  74. data/lib/puppet/indirector/file_server.rb +1 -1
  75. data/lib/puppet/indirector/node/ldap.rb +19 -3
  76. data/lib/puppet/indirector/request.rb +10 -6
  77. data/lib/puppet/indirector/rest.rb +11 -12
  78. data/lib/puppet/info_service/class_information_service.rb +1 -1
  79. data/lib/puppet/interface/action.rb +11 -0
  80. data/lib/puppet/interface/action_builder.rb +8 -0
  81. data/lib/puppet/interface/option_manager.rb +1 -1
  82. data/lib/puppet/loaders.rb +2 -0
  83. data/lib/puppet/module.rb +6 -2
  84. data/lib/puppet/module_tool/applications/builder.rb +4 -0
  85. data/lib/puppet/module_tool/applications/installer.rb +3 -0
  86. data/lib/puppet/module_tool/applications/uninstaller.rb +3 -0
  87. data/lib/puppet/module_tool/applications/unpacker.rb +1 -1
  88. data/lib/puppet/module_tool/applications/upgrader.rb +3 -0
  89. data/lib/puppet/module_tool/installed_modules.rb +1 -1
  90. data/lib/puppet/module_tool/metadata.rb +0 -1
  91. data/lib/puppet/network/authstore.rb +1 -1
  92. data/lib/puppet/network/http/api/indirected_routes.rb +1 -1
  93. data/lib/puppet/network/http/connection.rb +1 -9
  94. data/lib/puppet/network/http/factory.rb +0 -3
  95. data/lib/puppet/network/http/webrick.rb +1 -0
  96. data/lib/puppet/network/rights.rb +1 -1
  97. data/lib/puppet/node.rb +53 -0
  98. data/lib/puppet/node/environment.rb +1 -1
  99. data/lib/puppet/parameter/boolean.rb +1 -1
  100. data/lib/puppet/parser.rb +1 -0
  101. data/lib/puppet/parser/abstract_compiler.rb +36 -0
  102. data/lib/puppet/parser/ast/branch.rb +1 -1
  103. data/lib/puppet/parser/ast/pops_bridge.rb +8 -52
  104. data/lib/puppet/parser/compiler.rb +4 -54
  105. data/lib/puppet/parser/functions.rb +0 -1
  106. data/lib/puppet/parser/functions/create_resources.rb +6 -0
  107. data/lib/puppet/parser/functions/fqdn_rand.rb +6 -2
  108. data/lib/puppet/parser/functions/inline_template.rb +6 -0
  109. data/lib/puppet/parser/functions/new.rb +47 -32
  110. data/lib/puppet/parser/functions/realize.rb +6 -0
  111. data/lib/puppet/parser/functions/return.rb +1 -22
  112. data/lib/puppet/parser/functions/reverse_each.rb +1 -1
  113. data/lib/puppet/parser/functions/scanf.rb +1 -1
  114. data/lib/puppet/parser/functions/sha256.rb +5 -0
  115. data/lib/puppet/parser/functions/tag.rb +6 -0
  116. data/lib/puppet/parser/functions/tagged.rb +6 -0
  117. data/lib/puppet/parser/functions/template.rb +5 -0
  118. data/lib/puppet/parser/scope.rb +28 -4
  119. data/lib/puppet/parser/script_compiler.rb +118 -0
  120. data/lib/puppet/parser/type_loader.rb +1 -1
  121. data/lib/puppet/pops.rb +1 -1
  122. data/lib/puppet/pops/evaluator/access_operator.rb +38 -4
  123. data/lib/puppet/pops/evaluator/closure.rb +12 -4
  124. data/lib/puppet/pops/evaluator/compare_operator.rb +4 -4
  125. data/lib/puppet/pops/evaluator/epp_evaluator.rb +13 -0
  126. data/lib/puppet/pops/evaluator/evaluator_impl.rb +38 -10
  127. data/lib/puppet/pops/evaluator/literal_evaluator.rb +1 -1
  128. data/lib/puppet/pops/evaluator/runtime3_converter.rb +1 -1
  129. data/lib/puppet/pops/evaluator/runtime3_support.rb +2 -3
  130. data/lib/puppet/pops/functions/dispatch.rb +6 -5
  131. data/lib/puppet/pops/functions/function.rb +2 -2
  132. data/lib/puppet/pops/issues.rb +34 -2
  133. data/lib/puppet/pops/loader/base_loader.rb +10 -0
  134. data/lib/puppet/pops/loader/dependency_loader.rb +7 -0
  135. data/lib/puppet/pops/loader/loader.rb +21 -2
  136. data/lib/puppet/pops/loader/loader_paths.rb +180 -30
  137. data/lib/puppet/pops/loader/module_loaders.rb +202 -33
  138. data/lib/puppet/pops/loader/puppet_plan_instantiator.rb +84 -0
  139. data/lib/puppet/pops/loader/puppet_resource_type_impl_instantiator.rb +9 -9
  140. data/lib/puppet/pops/loader/ruby_data_type_instantiator.rb +40 -0
  141. data/lib/puppet/pops/loader/runtime3_type_loader.rb +6 -1
  142. data/lib/puppet/pops/loader/static_loader.rb +23 -8
  143. data/lib/puppet/pops/loader/task_instantiator.rb +69 -0
  144. data/lib/puppet/pops/loader/type_definition_instantiator.rb +4 -0
  145. data/lib/puppet/pops/loaders.rb +122 -11
  146. data/lib/puppet/pops/lookup/data_dig_function_provider.rb +1 -1
  147. data/lib/puppet/pops/lookup/interpolation.rb +1 -1
  148. data/lib/puppet/pops/lookup/lookup_adapter.rb +0 -1
  149. data/lib/puppet/pops/model/ast.pp +3 -0
  150. data/lib/puppet/pops/model/ast.rb +34 -1
  151. data/lib/puppet/pops/model/factory.rb +30 -3
  152. data/lib/puppet/pops/model/model_label_provider.rb +1 -0
  153. data/lib/puppet/pops/model/model_tree_dumper.rb +12 -1
  154. data/lib/puppet/pops/model/tree_dumper.rb +1 -1
  155. data/lib/puppet/pops/parser/code_merger.rb +2 -2
  156. data/lib/puppet/pops/parser/egrammar.ra +44 -15
  157. data/lib/puppet/pops/parser/eparser.rb +1687 -1571
  158. data/lib/puppet/pops/parser/epp_support.rb +1 -3
  159. data/lib/puppet/pops/parser/evaluating_parser.rb +1 -1
  160. data/lib/puppet/pops/parser/interpolation_support.rb +2 -2
  161. data/lib/puppet/pops/parser/lexer2.rb +4 -4
  162. data/lib/puppet/pops/parser/lexer_support.rb +2 -2
  163. data/lib/puppet/pops/parser/locatable.rb +1 -1
  164. data/lib/puppet/pops/parser/locator.rb +7 -13
  165. data/lib/puppet/pops/parser/parser_support.rb +3 -3
  166. data/lib/puppet/pops/parser/slurp_support.rb +0 -3
  167. data/lib/puppet/pops/pcore.rb +45 -0
  168. data/lib/puppet/pops/resource/param.rb +1 -1
  169. data/lib/puppet/pops/resource/resource_type_impl.rb +1 -1
  170. data/lib/puppet/pops/serialization/abstract_reader.rb +4 -0
  171. data/lib/puppet/pops/serialization/abstract_writer.rb +6 -0
  172. data/lib/puppet/pops/serialization/extension.rb +1 -0
  173. data/lib/puppet/pops/serialization/from_data_converter.rb +64 -10
  174. data/lib/puppet/pops/serialization/json_path.rb +2 -1
  175. data/lib/puppet/pops/serialization/object.rb +3 -4
  176. data/lib/puppet/pops/serialization/serializer.rb +2 -1
  177. data/lib/puppet/pops/serialization/to_data_converter.rb +7 -3
  178. data/lib/puppet/pops/time/timespan.rb +1 -1
  179. data/lib/puppet/pops/types/iterable.rb +38 -9
  180. data/lib/puppet/pops/types/p_init_type.rb +1 -1
  181. data/lib/puppet/pops/types/p_meta_type.rb +4 -0
  182. data/lib/puppet/pops/types/p_object_type.rb +146 -14
  183. data/lib/puppet/pops/types/p_object_type_extension.rb +218 -0
  184. data/lib/puppet/pops/types/p_sem_ver_range_type.rb +0 -1
  185. data/lib/puppet/pops/types/p_sem_ver_type.rb +10 -2
  186. data/lib/puppet/pops/types/p_type_set_type.rb +0 -1
  187. data/lib/puppet/pops/types/p_uri_type.rb +190 -0
  188. data/lib/puppet/pops/types/puppet_object.rb +15 -1
  189. data/lib/puppet/pops/types/ruby_generator.rb +46 -54
  190. data/lib/puppet/pops/types/string_converter.rb +22 -1
  191. data/lib/puppet/pops/types/type_acceptor.rb +1 -1
  192. data/lib/puppet/pops/types/type_calculator.rb +13 -4
  193. data/lib/puppet/pops/types/type_factory.rb +29 -5
  194. data/lib/puppet/pops/types/type_formatter.rb +67 -4
  195. data/lib/puppet/pops/types/type_parser.rb +92 -4
  196. data/lib/puppet/pops/types/type_with_members.rb +43 -0
  197. data/lib/puppet/pops/types/types.rb +212 -80
  198. data/lib/puppet/pops/validation/checker4_0.rb +10 -6
  199. data/lib/puppet/pops/validation/tasks_checker.rb +60 -0
  200. data/lib/puppet/pops/validation/validator_factory_4_0.rb +6 -1
  201. data/lib/puppet/property.rb +1 -1
  202. data/lib/puppet/provider.rb +18 -8
  203. data/lib/puppet/provider/augeas/augeas.rb +3 -4
  204. data/lib/puppet/provider/exec.rb +0 -2
  205. data/lib/puppet/provider/group/groupadd.rb +25 -1
  206. data/lib/puppet/provider/group/windows_adsi.rb +7 -4
  207. data/lib/puppet/provider/mount.rb +25 -8
  208. data/lib/puppet/provider/nameservice.rb +9 -4
  209. data/lib/puppet/provider/nameservice/directoryservice.rb +3 -3
  210. data/lib/puppet/provider/nameservice/objectadd.rb +13 -24
  211. data/lib/puppet/provider/nameservice/pw.rb +14 -14
  212. data/lib/puppet/provider/package/appdmg.rb +0 -1
  213. data/lib/puppet/provider/package/apple.rb +0 -1
  214. data/lib/puppet/provider/package/gem.rb +2 -2
  215. data/lib/puppet/provider/package/macports.rb +2 -2
  216. data/lib/puppet/provider/package/pkg.rb +3 -0
  217. data/lib/puppet/provider/package/pkgdmg.rb +0 -1
  218. data/lib/puppet/provider/package/portage.rb +0 -1
  219. data/lib/puppet/provider/package/yum.rb +23 -8
  220. data/lib/puppet/provider/package/zypper.rb +2 -2
  221. data/lib/puppet/provider/scheduled_task/win32_taskscheduler.rb +2 -2
  222. data/lib/puppet/provider/service/init.rb +1 -0
  223. data/lib/puppet/provider/service/launchd.rb +6 -7
  224. data/lib/puppet/provider/service/redhat.rb +3 -2
  225. data/lib/puppet/provider/service/systemd.rb +2 -2
  226. data/lib/puppet/provider/ssh_authorized_key/parsed.rb +1 -1
  227. data/lib/puppet/provider/user/aix.rb +3 -2
  228. data/lib/puppet/provider/user/openbsd.rb +1 -1
  229. data/lib/puppet/provider/user/pw.rb +1 -1
  230. data/lib/puppet/provider/user/user_role_add.rb +7 -1
  231. data/lib/puppet/provider/user/useradd.rb +36 -6
  232. data/lib/puppet/provider/user/windows_adsi.rb +1 -1
  233. data/lib/puppet/provider/yumrepo/inifile.rb +2 -4
  234. data/lib/puppet/provider/zfs/zfs.rb +23 -3
  235. data/lib/puppet/provider/zpool/zpool.rb +1 -1
  236. data/lib/puppet/reference/configuration.rb +0 -2
  237. data/lib/puppet/reference/type.rb +0 -1
  238. data/lib/puppet/resource.rb +1 -2
  239. data/lib/puppet/resource/catalog.rb +1 -1
  240. data/lib/puppet/resource/status.rb +0 -1
  241. data/lib/puppet/resource/type.rb +4 -4
  242. data/lib/puppet/resource/type_collection.rb +1 -1
  243. data/lib/puppet/settings/base_setting.rb +1 -1
  244. data/lib/puppet/settings/environment_conf.rb +0 -1
  245. data/lib/puppet/settings/ini_file.rb +66 -12
  246. data/lib/puppet/ssl/certificate_authority.rb +1 -1
  247. data/lib/puppet/ssl/certificate_request.rb +2 -2
  248. data/lib/puppet/ssl/certificate_revocation_list.rb +2 -1
  249. data/lib/puppet/ssl/certificate_signer.rb +11 -0
  250. data/lib/puppet/ssl/host.rb +2 -2
  251. data/lib/puppet/syntax_checkers/base64.rb +1 -1
  252. data/lib/puppet/transaction.rb +37 -14
  253. data/lib/puppet/transaction/report.rb +3 -1
  254. data/lib/puppet/type.rb +17 -4
  255. data/lib/puppet/type/cron.rb +1 -1
  256. data/lib/puppet/type/exec.rb +5 -4
  257. data/lib/puppet/type/file.rb +3 -3
  258. data/lib/puppet/type/file/checksum.rb +7 -1
  259. data/lib/puppet/type/file/checksum_value.rb +4 -3
  260. data/lib/puppet/type/group.rb +3 -0
  261. data/lib/puppet/type/k5login.rb +101 -0
  262. data/lib/puppet/type/macauthorization.rb +1 -1
  263. data/lib/puppet/type/mount.rb +6 -2
  264. data/lib/puppet/type/tidy.rb +6 -4
  265. data/lib/puppet/type/user.rb +26 -39
  266. data/lib/puppet/type/yumrepo.rb +9 -0
  267. data/lib/puppet/type/zfs.rb +4 -0
  268. data/lib/puppet/util.rb +8 -15
  269. data/lib/puppet/util/character_encoding.rb +2 -2
  270. data/lib/puppet/util/checksums.rb +82 -1
  271. data/lib/puppet/util/errors.rb +0 -2
  272. data/lib/puppet/util/filetype.rb +2 -2
  273. data/lib/puppet/util/json_lockfile.rb +1 -1
  274. data/lib/puppet/util/log.rb +1 -1
  275. data/lib/puppet/util/log/destinations.rb +10 -1
  276. data/lib/puppet/util/monkey_patches.rb +1 -1
  277. data/lib/puppet/util/network_device/cisco/device.rb +5 -5
  278. data/lib/puppet/util/network_device/config.rb +2 -3
  279. data/lib/puppet/util/platform.rb +13 -0
  280. data/lib/puppet/util/plist.rb +4 -4
  281. data/lib/puppet/util/rdoc/generators/puppet_generator.rb +2 -2
  282. data/lib/puppet/util/rdoc/parser/puppet_parser_rdoc2.rb +1 -1
  283. data/lib/puppet/util/reference.rb +8 -1
  284. data/lib/puppet/util/windows/adsi.rb +18 -15
  285. data/lib/puppet/util/windows/principal.rb +6 -7
  286. data/lib/puppet/util/windows/process.rb +1 -1
  287. data/lib/puppet/util/windows/registry.rb +2 -2
  288. data/lib/puppet/util/windows/sid.rb +7 -62
  289. data/lib/puppet/vendor/deep_merge/README.md +2 -2
  290. data/lib/puppet/vendor/pathspec/lib/pathspec/gitignorespec.rb +18 -18
  291. data/lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version.rb +2 -2
  292. data/lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb +5 -5
  293. data/lib/puppet/vendor/semantic_puppet/locales/config.yaml +1 -1
  294. data/lib/puppet/version.rb +1 -1
  295. data/lib/puppet_pal.rb +874 -0
  296. data/locales/ja/puppet.po +140 -163
  297. data/locales/puppet.pot +940 -597
  298. data/man/man5/puppet.conf.5 +16 -91
  299. data/man/man8/puppet-agent.8 +2 -6
  300. data/man/man8/puppet-apply.8 +2 -2
  301. data/man/man8/puppet-ca.8 +1 -1
  302. data/man/man8/puppet-catalog.8 +1 -1
  303. data/man/man8/puppet-cert.8 +1 -1
  304. data/man/man8/puppet-certificate.8 +1 -1
  305. data/man/man8/puppet-certificate_request.8 +1 -1
  306. data/man/man8/puppet-certificate_revocation_list.8 +1 -1
  307. data/man/man8/puppet-config.8 +1 -1
  308. data/man/man8/puppet-describe.8 +1 -1
  309. data/man/man8/puppet-device.8 +11 -33
  310. data/man/man8/puppet-doc.8 +1 -1
  311. data/man/man8/puppet-epp.8 +1 -1
  312. data/man/man8/puppet-facts.8 +1 -1
  313. data/man/man8/puppet-filebucket.8 +4 -22
  314. data/man/man8/puppet-generate.8 +1 -1
  315. data/man/man8/puppet-help.8 +1 -1
  316. data/man/man8/puppet-key.8 +1 -1
  317. data/man/man8/puppet-lookup.8 +1 -1
  318. data/man/man8/puppet-man.8 +1 -1
  319. data/man/man8/puppet-master.8 +1 -1
  320. data/man/man8/puppet-module.8 +2 -11
  321. data/man/man8/puppet-node.8 +1 -1
  322. data/man/man8/puppet-parser.8 +1 -1
  323. data/man/man8/puppet-plugin.8 +1 -1
  324. data/man/man8/puppet-report.8 +1 -1
  325. data/man/man8/puppet-resource.8 +1 -1
  326. data/man/man8/puppet-status.8 +1 -1
  327. data/man/man8/puppet.8 +2 -2
  328. data/spec/integration/application/lookup_spec.rb +0 -21
  329. data/spec/integration/parser/compiler_spec.rb +18 -0
  330. data/spec/integration/parser/script_compiler_spec.rb +113 -0
  331. data/spec/integration/provider/mount_spec.rb +2 -0
  332. data/spec/integration/type/file_spec.rb +11 -3
  333. data/spec/integration/util/windows/adsi_spec.rb +1 -86
  334. data/spec/integration/util/windows/principal_spec.rb +1 -10
  335. data/spec/shared_contexts/checksum.rb +4 -1
  336. data/spec/shared_contexts/digests.rb +46 -1
  337. data/spec/shared_contexts/types_setup.rb +8 -3
  338. data/spec/unit/agent_spec.rb +2 -2
  339. data/spec/unit/application/cert_spec.rb +5 -17
  340. data/spec/unit/application/device_spec.rb +2 -96
  341. data/spec/unit/application/filebucket_spec.rb +18 -4
  342. data/spec/unit/configurer/plugin_handler_spec.rb +5 -32
  343. data/spec/unit/configurer_spec.rb +3 -3
  344. data/spec/unit/datatypes_spec.rb +304 -0
  345. data/spec/unit/defaults_spec.rb +41 -20
  346. data/spec/unit/face/config_spec.rb +46 -1
  347. data/spec/unit/face/epp_face_spec.rb +7 -3
  348. data/spec/unit/face/module/search_spec.rb +11 -0
  349. data/spec/unit/face/parser_spec.rb +2 -2
  350. data/spec/unit/file_bucket/dipper_spec.rb +12 -1
  351. data/spec/unit/forge/module_release_spec.rb +70 -0
  352. data/spec/unit/functions/break_spec.rb +34 -2
  353. data/spec/unit/functions/contain_spec.rb +1 -0
  354. data/spec/unit/functions/convert_to_spec.rb +22 -0
  355. data/spec/unit/functions/epp_spec.rb +5 -0
  356. data/spec/unit/functions/include_spec.rb +15 -0
  357. data/spec/unit/functions/module_directory_spec.rb +43 -0
  358. data/spec/unit/functions/new_spec.rb +14 -14
  359. data/spec/unit/functions/require_spec.rb +2 -0
  360. data/spec/unit/functions/shared.rb +12 -0
  361. data/spec/unit/functions/step_spec.rb +1 -1
  362. data/spec/unit/functions4_spec.rb +49 -4
  363. data/spec/unit/indirector/catalog/compiler_spec.rb +3 -3
  364. data/spec/unit/indirector/file_bucket_file/file_spec.rb +148 -94
  365. data/spec/unit/indirector/node/ldap_spec.rb +15 -12
  366. data/spec/unit/indirector/rest_spec.rb +0 -43
  367. data/spec/unit/interface/action_spec.rb +33 -0
  368. data/spec/unit/module_tool/applications/builder_spec.rb +7 -0
  369. data/spec/unit/module_tool/applications/installer_spec.rb +8 -0
  370. data/spec/unit/module_tool/applications/uninstaller_spec.rb +8 -0
  371. data/spec/unit/module_tool/applications/upgrader_spec.rb +6 -0
  372. data/spec/unit/network/http/connection_spec.rb +1 -1
  373. data/spec/unit/network/http/factory_spec.rb +28 -35
  374. data/spec/unit/parser/compiler_spec.rb +0 -8
  375. data/spec/unit/parser/environment_compiler_spec.rb +36 -0
  376. data/spec/unit/parser/functions/create_resources_spec.rb +9 -0
  377. data/spec/unit/parser/functions/inline_template_spec.rb +7 -0
  378. data/spec/unit/parser/functions/realize_spec.rb +9 -0
  379. data/spec/unit/parser/functions/tag_spec.rb +7 -0
  380. data/spec/unit/parser/functions/tagged_spec.rb +25 -0
  381. data/spec/unit/parser/functions/template_spec.rb +8 -0
  382. data/spec/unit/parser/scope_spec.rb +19 -0
  383. data/spec/unit/pops/evaluator/conditionals_spec.rb +1 -1
  384. data/spec/unit/pops/loaders/loader_spec.rb +516 -0
  385. data/spec/unit/pops/loaders/loaders_spec.rb +11 -0
  386. data/spec/unit/pops/loaders/module_loaders_spec.rb +43 -0
  387. data/spec/unit/pops/loaders/static_loader_spec.rb +15 -7
  388. data/spec/unit/pops/model/model_spec.rb +5 -0
  389. data/spec/unit/pops/parser/lexer2_spec.rb +15 -0
  390. data/spec/unit/pops/parser/locator_spec.rb +20 -0
  391. data/spec/unit/pops/parser/parse_basic_expressions_spec.rb +33 -0
  392. data/spec/unit/pops/parser/parse_calls_spec.rb +28 -0
  393. data/spec/unit/pops/parser/parse_conditionals_spec.rb +12 -0
  394. data/spec/unit/pops/parser/parse_plan_spec.rb +48 -0
  395. data/spec/unit/pops/serialization/packer_spec.rb +8 -0
  396. data/spec/unit/pops/serialization/serialization_spec.rb +30 -0
  397. data/spec/unit/pops/serialization/to_from_hr_spec.rb +31 -0
  398. data/spec/unit/pops/types/error_spec.rb +207 -0
  399. data/spec/unit/pops/types/p_init_type_spec.rb +98 -0
  400. data/spec/unit/pops/types/p_object_type_spec.rb +275 -10
  401. data/spec/unit/pops/types/p_uri_type_spec.rb +191 -0
  402. data/spec/unit/pops/types/ruby_generator_spec.rb +82 -44
  403. data/spec/unit/pops/types/task_spec.rb +353 -0
  404. data/spec/unit/pops/types/type_calculator_spec.rb +76 -5
  405. data/spec/unit/pops/types/type_formatter_spec.rb +31 -13
  406. data/spec/unit/pops/types/type_parser_spec.rb +13 -1
  407. data/spec/unit/pops/types/types_spec.rb +60 -0
  408. data/spec/unit/pops/validator/validator_spec.rb +76 -0
  409. data/spec/unit/provider/group/groupadd_spec.rb +77 -1
  410. data/spec/unit/provider/group/pw_spec.rb +4 -4
  411. data/spec/unit/provider/group/windows_adsi_spec.rb +22 -79
  412. data/spec/unit/provider/mount_spec.rb +18 -5
  413. data/spec/unit/provider/nameservice_spec.rb +5 -5
  414. data/spec/unit/provider/package/dnf_spec.rb +2 -2
  415. data/spec/unit/provider/package/gem_spec.rb +1 -1
  416. data/spec/unit/provider/package/pkg_spec.rb +3 -0
  417. data/spec/unit/provider/package/yum_spec.rb +40 -0
  418. data/spec/unit/provider/service/launchd_spec.rb +2 -1
  419. data/spec/unit/provider/service/redhat_spec.rb +5 -0
  420. data/spec/unit/provider/service/systemd_spec.rb +1 -1
  421. data/spec/unit/provider/user/hpux_spec.rb +2 -2
  422. data/spec/unit/provider/user/openbsd_spec.rb +2 -2
  423. data/spec/unit/provider/user/pw_spec.rb +14 -14
  424. data/spec/unit/provider/user/user_role_add_spec.rb +19 -2
  425. data/spec/unit/provider/user/useradd_spec.rb +188 -22
  426. data/spec/unit/provider/user/windows_adsi_spec.rb +4 -4
  427. data/spec/unit/provider/zfs/zfs_spec.rb +55 -1
  428. data/spec/unit/provider_spec.rb +48 -0
  429. data/spec/unit/puppet_pal_2pec.rb +1005 -0
  430. data/spec/unit/puppet_pal_spec.rb +11 -0
  431. data/spec/unit/settings/ini_file_spec.rb +313 -2
  432. data/spec/unit/ssl/certificate_request_spec.rb +42 -1
  433. data/spec/unit/ssl/certificate_revocation_list_spec.rb +2 -1
  434. data/spec/unit/transaction/report_spec.rb +1 -0
  435. data/spec/unit/transaction_spec.rb +112 -21
  436. data/spec/unit/type/file/checksum_spec.rb +20 -0
  437. data/spec/unit/type/file_spec.rb +8 -0
  438. data/spec/unit/type/group_spec.rb +8 -0
  439. data/spec/unit/type/k5login_spec.rb +22 -1
  440. data/spec/unit/type/scheduled_task_spec.rb +15 -0
  441. data/spec/unit/type/user_spec.rb +11 -1
  442. data/spec/unit/type/yumrepo_spec.rb +5 -0
  443. data/spec/unit/util/checksums_spec.rb +3 -3
  444. data/spec/unit/util/log/destinations_spec.rb +14 -0
  445. data/spec/unit/util/network_device/cisco/device_spec.rb +1 -1
  446. data/spec/unit/util/plist_spec.rb +3 -3
  447. data/spec/unit/util/windows/adsi_spec.rb +27 -31
  448. data/spec/unit/util/windows/sid_spec.rb +15 -86
  449. data/spec/unit/util_spec.rb +17 -3
  450. data/tasks/manpages.rake +1 -1
  451. metadata +218 -180
  452. data/lib/puppet/bindings.rb +0 -148
  453. data/lib/puppet/configurer/downloader_factory.rb +0 -44
  454. data/spec/unit/configurer/downloader_factory_spec.rb +0 -129
@@ -32,10 +32,9 @@ module Puppet::Util::Windows::SID
32
32
  @sid_bytes == compare.sid_bytes
33
33
  end
34
34
 
35
- # returns authority qualified account name
36
- # prefer to compare Principal instances with == operator or by #sid
35
+ # added for backward compatibility
37
36
  def to_s
38
- @domain_account
37
+ @sid
39
38
  end
40
39
 
41
40
  # = 8 + max sub identifiers (15) * 4
@@ -65,14 +64,14 @@ module Puppet::Util::Windows::SID
65
64
  last_error = FFI.errno
66
65
 
67
66
  if (success == FFI::WIN32_FALSE && last_error != ERROR_INSUFFICIENT_BUFFER)
68
- raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountNameW with account: %{account_name}') % { account_name: account_name}, last_error)
67
+ raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountNameW'), last_error)
69
68
  end
70
69
 
71
70
  FFI::MemoryPointer.new(:lpwstr, domain_length_ptr.read_dword) do |domain_ptr|
72
71
  if LookupAccountNameW(system_name_ptr, account_name_ptr,
73
72
  sid_ptr, sid_length_ptr,
74
73
  domain_ptr, domain_length_ptr, name_use_enum_ptr) == FFI::WIN32_FALSE
75
- raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountNameW with account: %{account_name}') % { account_name: account_name} )
74
+ raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountNameW'))
76
75
  end
77
76
 
78
77
  # with a SID returned, loop back through lookup_account_sid to retrieve official name
@@ -117,14 +116,14 @@ module Puppet::Util::Windows::SID
117
116
  last_error = FFI.errno
118
117
 
119
118
  if (success == FFI::WIN32_FALSE && last_error != ERROR_INSUFFICIENT_BUFFER)
120
- raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountSidW with bytes: %{sid_bytes}') % { sid_bytes: sid_bytes}, last_error)
119
+ raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountSidW'), last_error)
121
120
  end
122
121
 
123
122
  FFI::MemoryPointer.new(:lpwstr, name_length_ptr.read_dword) do |name_ptr|
124
123
  FFI::MemoryPointer.new(:lpwstr, domain_length_ptr.read_dword) do |domain_ptr|
125
124
  if LookupAccountSidW(system_name_ptr, sid_ptr, name_ptr, name_length_ptr,
126
125
  domain_ptr, domain_length_ptr, name_use_enum_ptr) == FFI::WIN32_FALSE
127
- raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountSidW with bytes: %{sid_bytes}') % { sid_bytes: sid_bytes} )
126
+ raise Puppet::Util::Windows::Error.new(_('Failed to call LookupAccountSidW'))
128
127
  end
129
128
 
130
129
  return new(
@@ -232,7 +232,7 @@ module Puppet::Util::Windows::Process
232
232
  # Note - Some env variable names start with '=' and are excluded from the return value
233
233
  # Note - The env_ptr MUST be freed using the FreeEnvironmentStringsW function
234
234
  # Note - There is no technical limitation to the size of the environment block returned.
235
- # However a pracitcal limit of 64K is used as no single environment variable can exceed 32KB
235
+ # However a practical limit of 64K is used as no single environment variable can exceed 32KB
236
236
  def get_environment_strings
237
237
  env_ptr = GetEnvironmentStringsW()
238
238
 
@@ -44,7 +44,7 @@ module Puppet::Util::Windows
44
44
  index = 0
45
45
  subkey = nil
46
46
 
47
- subkey_max_len, value_max_len = reg_query_info_key_max_lengths(key)
47
+ subkey_max_len, _ = reg_query_info_key_max_lengths(key)
48
48
 
49
49
  begin
50
50
  subkey, filetime = reg_enum_key(key, index, subkey_max_len)
@@ -69,7 +69,7 @@ module Puppet::Util::Windows
69
69
  index = 0
70
70
  subkey = nil
71
71
 
72
- subkey_max_len, value_max_len = reg_query_info_key_max_lengths(key)
72
+ _, value_max_len = reg_query_info_key_max_lengths(key)
73
73
 
74
74
  begin
75
75
  subkey, type, data = reg_enum_value(key, index, value_max_len)
@@ -52,18 +52,18 @@ module Puppet::Util::Windows
52
52
  # 'BUILTIN\Administrators', or 'S-1-5-32-544', and will return the
53
53
  # SID. Returns nil if the account doesn't exist.
54
54
  def name_to_sid(name)
55
- sid = name_to_principal(name)
55
+ sid = name_to_sid_object(name)
56
56
 
57
57
  sid ? sid.sid : nil
58
58
  end
59
59
  module_function :name_to_sid
60
60
 
61
- # Convert an account name, e.g. 'Administrators' into a Principal::SID object,
61
+ # Convert an account name, e.g. 'Administrators' into a SID object,
62
62
  # e.g. 'S-1-5-32-544'. The name can be specified as 'Administrators',
63
63
  # 'BUILTIN\Administrators', or 'S-1-5-32-544', and will return the
64
64
  # SID object. Returns nil if the account doesn't exist.
65
65
  # This method returns a SID::Principal with the account, domain, SID, etc
66
- def name_to_principal(name)
66
+ def name_to_sid_object(name)
67
67
  # Apparently, we accept a symbol..
68
68
  name = name.to_s.strip if name
69
69
 
@@ -71,7 +71,6 @@ module Puppet::Util::Windows
71
71
  raw_sid_bytes = nil
72
72
  begin
73
73
  string_to_sid_ptr(name) do |sid_ptr|
74
- valid = ! sid_ptr.nil? && ! sid_ptr.null?
75
74
  raw_sid_bytes = sid_ptr.read_array_of_uchar(get_length_sid(sid_ptr))
76
75
  end
77
76
  rescue
@@ -81,50 +80,21 @@ module Puppet::Util::Windows
81
80
  rescue
82
81
  nil
83
82
  end
84
- module_function :name_to_principal
85
- class << self; alias name_to_sid_object name_to_principal; end
83
+ module_function :name_to_sid_object
86
84
 
87
- # Converts an octet string array of bytes to a SID::Principal object,
85
+ # Converts an octet string array of bytes to a SID object,
88
86
  # e.g. [1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0] is the representation for
89
87
  # S-1-5-18, the local 'SYSTEM' account.
90
88
  # Raises an Error for nil or non-array input.
91
89
  # This method returns a SID::Principal with the account, domain, SID, etc
92
- def octet_string_to_principal(bytes)
90
+ def octet_string_to_sid_object(bytes)
93
91
  if !bytes || !bytes.respond_to?('pack') || bytes.empty?
94
92
  raise Puppet::Util::Windows::Error.new(_("Octet string must be an array of bytes"))
95
93
  end
96
94
 
97
95
  Principal.lookup_account_sid(bytes)
98
96
  end
99
- module_function :octet_string_to_principal
100
- class << self; alias octet_string_to_sid_object octet_string_to_principal; end
101
-
102
- # Converts a COM instance of IAdsUser or IAdsGroup to a SID::Principal object,
103
- # Raises an Error for nil or an object without an objectSID / Name property.
104
- # This method returns a SID::Principal with the account, domain, SID, etc
105
- # This method will return instances even when the SID is unresolvable, as
106
- # may be the case when domain users have been added to local groups, but
107
- # removed from the domain
108
- def ads_to_principal(ads_object)
109
- if !ads_object || !ads_object.respond_to?(:ole_respond_to?) ||
110
- !ads_object.ole_respond_to?(:objectSID) || !ads_object.ole_respond_to?(:Name)
111
- raise Puppet::Error.new("ads_object must be an IAdsUser or IAdsGroup instance")
112
- end
113
- octet_string_to_principal(ads_object.objectSID)
114
- rescue Puppet::Util::Windows::Error => e
115
- # if the error is not a lookup / mapping problem, immediately re-raise
116
- raise if e.code != ERROR_NONE_MAPPED
117
-
118
- # if the Name property isn't formatted like a SID, OR
119
- if !valid_sid?(ads_object.Name) ||
120
- # if the objectSID doesn't match the Name property, also raise
121
- ((converted = octet_string_to_sid_string(ads_object.objectSID)) != ads_object.Name)
122
- raise Puppet::Error.new("ads_object Name: #{ads_object.Name} invalid or does not match objectSID: #{ads_object.objectSID} (#{converted})", e)
123
- end
124
-
125
- unresolved_principal(ads_object.Name, ads_object.objectSID)
126
- end
127
- module_function :ads_to_principal
97
+ module_function :octet_string_to_sid_object
128
98
 
129
99
  # Convert a SID string, e.g. "S-1-5-32-544" to a name,
130
100
  # e.g. 'BUILTIN\Administrators'. Returns nil if an account
@@ -134,7 +104,6 @@ module Puppet::Util::Windows
134
104
  sid_bytes = []
135
105
  begin
136
106
  string_to_sid_ptr(value) do |ptr|
137
- valid = ! ptr.nil? && ! ptr.null?
138
107
  sid_bytes = ptr.read_array_of_uchar(get_length_sid(ptr))
139
108
  end
140
109
  rescue Puppet::Util::Windows::Error => e
@@ -222,30 +191,6 @@ module Puppet::Util::Windows
222
191
  end
223
192
  module_function :get_length_sid
224
193
 
225
- def octet_string_to_sid_string(sid_bytes)
226
- sid_string = nil
227
-
228
- FFI::MemoryPointer.new(:byte, sid_bytes.length) do |sid_ptr|
229
- sid_ptr.write_array_of_uchar(sid_bytes)
230
- sid_string = Puppet::Util::Windows::SID.sid_ptr_to_string(sid_ptr)
231
- end
232
-
233
- sid_string
234
- end
235
- module_function :octet_string_to_sid_string
236
-
237
- # @api private
238
- def self.unresolved_principal(name, sid_bytes)
239
- Principal.new(
240
- name + " (unresolvable)", # account
241
- sid_bytes, # sid_bytes
242
- name, # sid string
243
- nil, #domain
244
- # https://msdn.microsoft.com/en-us/library/cc245534.aspx?f=255&MSPPError=-2147217396
245
- # Indicates that the type of object could not be determined. For example, no object with that SID exists.
246
- :SidTypeUnknown)
247
- end
248
-
249
194
  ffi_convention :stdcall
250
195
 
251
196
  # https://msdn.microsoft.com/en-us/library/windows/desktop/aa379151(v=vs.85).aspx
@@ -105,8 +105,8 @@ Simple Example Code
105
105
  y.deep_merge!(x)
106
106
  # results: y = {:x => [1,2,3,4,5]}
107
107
 
108
- Availablility
109
- =============
108
+ Availability
109
+ ============
110
110
 
111
111
  `deep_merge` was written by Steve Midgley, and is now maintained by Daniel DeLeo. The official home of `deep_merge` on the internet is now https://github.com/danielsdeleo/deep_merge
112
112
 
@@ -60,7 +60,7 @@ class GitIgnoreSpec < RegexSpec
60
60
  pattern_segs.shift
61
61
  else
62
62
  # A pattern without a beginning slash ('/') will match any
63
- # descendant path. This is equivilent to "**/{pattern}". So,
63
+ # descendant path. This is equivalent to "**/{pattern}". So,
64
64
  # prepend with double-asterisks to make pattern relative to
65
65
  # root.
66
66
  if pattern_segs.length == 1 && pattern_segs[0] != '**'
@@ -70,7 +70,7 @@ class GitIgnoreSpec < RegexSpec
70
70
 
71
71
  # A pattern ending with a slash ('/') will match all descendant
72
72
  # paths of if it is a directory but not if it is a regular file.
73
- # This is equivilent to "{pattern}/**". So, set last segment to
73
+ # This is equivalent to "{pattern}/**". So, set last segment to
74
74
  # double asterisks to include all descendants.
75
75
  if pattern_segs[-1].empty?
76
76
  pattern_segs[-1] = '**'
@@ -185,13 +185,13 @@ class GitIgnoreSpec < RegexSpec
185
185
  elsif char == '?'
186
186
  regex += '[^/]'
187
187
 
188
- # Braket expression wildcard. Except for the beginning
189
- # exclamation mark, the whole braket expression can be used
188
+ # Bracket expression wildcard. Except for the beginning
189
+ # exclamation mark, the whole bracket expression can be used
190
190
  # directly as regex but we have to find where the expression
191
191
  # ends.
192
- # - "[][!]" matchs ']', '[' and '!'.
193
- # - "[]-]" matchs ']' and '-'.
194
- # - "[!]a-]" matchs any character except ']', 'a' and '-'.
192
+ # - "[][!]" matches ']', '[' and '!'.
193
+ # - "[]-]" matches ']' and '-'.
194
+ # - "[!]a-]" matches any character except ']', 'a' and '-'.
195
195
  elsif char == '['
196
196
  j = i
197
197
  # Pass brack expression negation.
@@ -199,13 +199,13 @@ class GitIgnoreSpec < RegexSpec
199
199
  j += 1
200
200
  end
201
201
 
202
- # Pass first closing braket if it is at the beginning of the
202
+ # Pass first closing bracket if it is at the beginning of the
203
203
  # expression.
204
204
  if j < pattern.size && pattern[j].chr == ']'
205
205
  j += 1
206
206
  end
207
207
 
208
- # Find closing braket. Stop once we reach the end or find it.
208
+ # Find closing bracket. Stop once we reach the end or find it.
209
209
  while j < pattern.size && pattern[j].chr != ']'
210
210
  j += 1
211
211
  end
@@ -214,12 +214,12 @@ class GitIgnoreSpec < RegexSpec
214
214
  if j < pattern.size
215
215
  expr = '['
216
216
 
217
- # Braket expression needs to be negated.
217
+ # Bracket expression needs to be negated.
218
218
  if pattern[i].chr == '!'
219
219
  expr += '^'
220
220
  i += 1
221
221
 
222
- # POSIX declares that the regex braket expression negation
222
+ # POSIX declares that the regex bracket expression negation
223
223
  # "[^...]" is undefined in a glob pattern. Python's
224
224
  # `fnmatch.translate()` escapes the caret ('^') as a
225
225
  # literal. To maintain consistency with undefined behavior,
@@ -236,26 +236,26 @@ class GitIgnoreSpec < RegexSpec
236
236
  end
237
237
 
238
238
 
239
- # Build regex braket expression. Escape slashes so they are
239
+ # Build regex bracket expression. Escape slashes so they are
240
240
  # treated as literal slashes by regex as defined by POSIX.
241
241
  expr += pattern[i..j].sub('\\', '\\\\')
242
242
 
243
- # Add regex braket expression to regex result.
243
+ # Add regex bracket expression to regex result.
244
244
  regex += expr
245
245
 
246
- # Found end of braket expression. Increment j to be one past
247
- # the closing braket:
246
+ # Found end of bracket expression. Increment j to be one past
247
+ # the closing bracket:
248
248
  #
249
249
  # [...]
250
250
  # ^ ^
251
251
  # i j
252
252
  #
253
253
  j += 1
254
- # Set i to one past the closing braket.
254
+ # Set i to one past the closing bracket.
255
255
  i = j
256
256
 
257
- # Failed to find closing braket, treat opening braket as a
258
- # braket literal instead of as an expression.
257
+ # Failed to find closing bracket, treat opening bracket as a
258
+ # bracket literal instead of as an expression.
259
259
  else
260
260
  regex += '\['
261
261
  end
@@ -161,7 +161,7 @@ module SemanticPuppet
161
161
  else
162
162
  # Compare all prerelease identifier segments that can be compared. Should
163
163
  # all segments compare equal up to the point where one of the prereleases
164
- # have no more segments, then the one with more segements is greater.
164
+ # have no more segments, then the one with more segments is greater.
165
165
  your_max = yours.size
166
166
  mine.each_with_index do |x, idx|
167
167
  # 'mine' win if 'your' list of segments is exhausted
@@ -181,7 +181,7 @@ module SemanticPuppet
181
181
  return cmp unless cmp == 0
182
182
  end
183
183
 
184
- # All segments, up to the point where at least one list of segement is exhausted,
184
+ # All segments, up to the point where at least one list of segment is exhausted,
185
185
  # compared equal. The one with the highest segment count wins.
186
186
  mine.size <=> your_max
187
187
  end
@@ -407,8 +407,8 @@ module SemanticPuppet
407
407
 
408
408
  # Merge two ranges so that the result matches the intersection of all matching versions.
409
409
  #
410
- # @param range [AbastractRange] the range to intersect with
411
- # @return [AbastractRange,nil] the intersection between the ranges
410
+ # @param range [AbstractRange] the range to intersect with
411
+ # @return [AbstractRange,nil] the intersection between the ranges
412
412
  #
413
413
  # @api private
414
414
  def intersection(range)
@@ -456,8 +456,8 @@ module SemanticPuppet
456
456
  # Merge two ranges so that the result matches the sum of all matching versions. A merge
457
457
  # is only possible when the ranges are either adjacent or have an overlap.
458
458
  #
459
- # @param other [AbastractRange] the range to merge with
460
- # @return [AbastractRange,nil] the result of the merge
459
+ # @param other [AbstractRange] the range to merge with
460
+ # @return [AbstractRange,nil] the result of the merge
461
461
  #
462
462
  # @api private
463
463
  def merge(other)
@@ -508,7 +508,7 @@ module SemanticPuppet
508
508
  # Checks if this matcher accepts a prerelease with the same major, minor, patch triple as the given version. Only matchers
509
509
  # where this has been explicitly stated will respond `true` to this method
510
510
  #
511
- # @return [Boolean] `true` if this matcher accepts a prerelase with the tuple from the given version
511
+ # @return [Boolean] `true` if this matcher accepts a prerelease with the tuple from the given version
512
512
  def test_prerelease?(_)
513
513
  false
514
514
  end
@@ -6,7 +6,7 @@ gettext:
6
6
  # called <project_name>.pot?
7
7
  project_name: 'semantic_puppet'
8
8
  # This is used in comments in the .pot and .po files to indicate what
9
- # project the files belong to and should bea little more desctiptive than
9
+ # project the files belong to and should be a little more descriptive than
10
10
  # <project_name>
11
11
  package_name: Semantic Puppet Gem
12
12
  # The locale that the default messages in the .pot file are in
@@ -6,7 +6,7 @@
6
6
  # Raketasks and such to set the version based on the output of `git describe`
7
7
 
8
8
  module Puppet
9
- PUPPETVERSION = '5.3.7'
9
+ PUPPETVERSION = '5.4.0'
10
10
 
11
11
  ##
12
12
  # version is a public API method intended to always provide a fast and
data/lib/puppet_pal.rb ADDED
@@ -0,0 +1,874 @@
1
+ # Puppet as a Library "PAL"
2
+
3
+ # Yes, this requires all of puppet for now because 'settings' and many other things...
4
+ require 'puppet'
5
+ require 'puppet/parser/script_compiler'
6
+
7
+ # This is the main entry point for "Puppet As a Library" PAL.
8
+ # This file should be required instead of "puppet"
9
+ # Initially, this will require ALL of puppet - over time this will change as the monolithical "puppet" is broken up
10
+ # into smaller components.
11
+ #
12
+ # @example Running a snippet of Puppet Language code
13
+ # require 'puppet_pal'
14
+ # result = Puppet::Pal.in_tmp_environment('pal_env', modulepath: ['/tmp/testmodules']) do |pal|
15
+ # pal.evaluate_script_string('1+2+3')
16
+ # end
17
+ # # The result is the value 6
18
+ #
19
+ # @example Calling a function
20
+ # require 'puppet_pal'
21
+ # result = Puppet::Pal.in_tmp_environment('pal_env', modulepath: ['/tmp/testmodules']) do |pal|
22
+ # pal.call_function('mymodule::myfunction', 10, 20)
23
+ # end
24
+ # # The result is what 'mymodule::myfunction' returns
25
+ #
26
+ module Puppet
27
+ module Pal
28
+
29
+ # A configured compiler as obtained in the callback from `with_script_compiler`.
30
+ # (Later, there may also be a catalog compiler available.)
31
+ #
32
+ class Compiler
33
+ attr_reader :internal_compiler
34
+ protected :internal_compiler
35
+
36
+ attr_reader :internal_evaluator
37
+ protected :internal_evaluator
38
+
39
+ def initialize(internal_compiler)
40
+ @internal_compiler = internal_compiler
41
+ @internal_evaluator = Puppet::Pops::Parser::EvaluatingParser.new
42
+ end
43
+
44
+ # Calls a function given by name with arguments specified in an `Array`, and optionally accepts a code block.
45
+ # @param function_name [String] the name of the function to call
46
+ # @param args [Object] the arguments to the function
47
+ # @param block [Proc] an optional callable block that is given to the called function
48
+ # @return [Object] what the called function returns
49
+ #
50
+ def call_function(function_name, *args, &block)
51
+ # TRANSLATORS: do not translate variable name strings in these assertions
52
+ Pal::assert_non_empty_string(function_name, 'function_name', false)
53
+ Pal::assert_type(Pal::T_ANY_ARRAY, args, 'args', false)
54
+ internal_evaluator.evaluator.external_call_function(function_name, args, topscope, &block)
55
+ end
56
+
57
+ # Returns a Puppet::Pal::FunctionSignature object or nil if function is not found
58
+ # The returned FunctionSignature has information about all overloaded signatures of the function
59
+ #
60
+ # @example using function_signature
61
+ # # returns true if 'myfunc' is callable with three integer arguments 1, 2, 3
62
+ # compiler.function_signature('myfunc').callable_with?([1,2,3])
63
+ #
64
+ # @param function_name [String] the name of the function to get a signature for
65
+ # @return [Puppet::Pal::FunctionSignature] a function signature, or nil if function not found
66
+ #
67
+ def function_signature(function_name)
68
+ loader = internal_compiler.loaders.private_environment_loader
69
+ if func = loader.load(:function, function_name)
70
+ return FunctionSignature.new(func.class)
71
+ end
72
+ # Could not find function
73
+ nil
74
+ end
75
+
76
+ # Returns an array of TypedName objects for all functions, optionally filtered by a regular expression.
77
+ # The returned array has more information than just the leaf name - the typical thing is to just get
78
+ # the name as showing the following example.
79
+ #
80
+ # Errors that occur during function discovery will either be logged as warnings or collected by the optional
81
+ # `error_collector` array. When provided, it will receive {Puppet::DataTypes::Error} instances describing
82
+ # each error in detail and no warnings will be logged.
83
+ #
84
+ # @example getting the names of all functions
85
+ # compiler.list_functions.map {|tn| tn.name }
86
+ #
87
+ # @param filter_regex [Regexp] an optional regexp that filters based on name (matching names are included in the result)
88
+ # @param error_collector [Array<Puppet::DataTypes::Error>] an optional array that will receive errors during load
89
+ # @return [Array<Puppet::Pops::Loader::TypedName>] an array of typed names
90
+ #
91
+ def list_functions(filter_regex = nil, error_collector = nil)
92
+ list_loadable_kind(:function, filter_regex, error_collector)
93
+ end
94
+
95
+ # Evaluates a string of puppet language code in top scope.
96
+ # A "source_file" reference to a source can be given - if not an actual file name, by convention the name should
97
+ # be bracketed with < > to indicate it is something symbolic; for example `<commandline>` if the string was given on the
98
+ # command line.
99
+ #
100
+ # If the given `puppet_code` is `nil` or an empty string, `nil` is returned, otherwise the result of evaluating the
101
+ # puppet language string. The given string must form a complete and valid expression/statement as an error is raised
102
+ # otherwise. That is, it is not possible to divide a compound expression by line and evaluate each line individually.
103
+ #
104
+ # @param puppet_code [String, nil] the puppet language code to evaluate, must be a complete expression/statement
105
+ # @param source_file [String, nil] an optional reference to a source (a file or symbolic name/location)
106
+ # @return [Object] what the `puppet_code` evaluates to
107
+ #
108
+ def evaluate_string(puppet_code, source_file = nil)
109
+ return nil if puppet_code.nil? || puppet_code == ''
110
+ unless puppet_code.is_a?(String)
111
+ raise ArgumentError, _("The argument 'puppet_code' must be a String, got %{type}") % { type: puppet_code.class }
112
+ end
113
+ evaluate(parse_string(puppet_code, source_file))
114
+ end
115
+
116
+ # Evaluates a puppet language file in top scope.
117
+ # The file must exist and contain valid puppet language code or an error is raised.
118
+ #
119
+ # @param file [Path, String] an absolute path to a file with puppet language code, must exist
120
+ # @return [Object] what the last evaluated expression in the file evaluated to
121
+ #
122
+ def evaluate_file(file)
123
+ evaluate(parse_file(file))
124
+ end
125
+
126
+ # Evaluates an AST obtained from `parse_string` or `parse_file` in topscope.
127
+ # If the ast is a `Puppet::Pops::Model::Program` (what is returned from the `parse` methods, any definitions
128
+ # in the program (that is, any function, plan, etc. that is defined will be made available for use).
129
+ #
130
+ # @param ast [Puppet::Pops::Model::PopsObject] typically the returned `Program` from the parse methods, but can be any `Expression`
131
+ # @returns [Object] whatever the ast evaluates to
132
+ #
133
+ def evaluate(ast)
134
+ if ast.is_a?(Puppet::Pops::Model::Program)
135
+ loaders = Puppet.lookup(:loaders)
136
+ loaders.instantiate_definitions(ast, loaders.public_environment_loader)
137
+ end
138
+ internal_evaluator.evaluate(topscope, ast)
139
+ end
140
+
141
+ # Produces a literal value if the AST obtained from `parse_string` or `parse_file` does not require any actual evaluation.
142
+ # This method is useful if obtaining an AST that represents literal values; string, integer, float, boolean, regexp, array, hash;
143
+ # for example from having read this from the command line or as values in some file.
144
+ #
145
+ # @param ast [Puppet::Pops::Model::PopsObject] typically the returned `Program` from the parse methods, but can be any `Expression`
146
+ # @returns [Object] whatever the literal value the ast evaluates to
147
+ #
148
+ def evaluate_literal(ast)
149
+ catch :not_literal do
150
+ return Puppet::Pops::Evaluator::LiteralEvaluator.new().literal(ast)
151
+ end
152
+ # TRANSLATORS, the 'ast' is the name of a parameter, do not translate
153
+ raise ArgumentError, _("The given 'ast' does not represent a literal value")
154
+ end
155
+
156
+ # Parses and validates a puppet language string and returns an instance of Puppet::Pops::Model::Program on success.
157
+ # If the content is not valid an error is raised.
158
+ #
159
+ # @param code_string [String] a puppet language string to parse and validate
160
+ # @param source_file [String] an optional reference to a file or other location in angled brackets
161
+ # @return [Puppet::Pops::Model::Program] returns a `Program` instance on success
162
+ #
163
+ def parse_string(code_string, source_file = nil)
164
+ unless code_string.is_a?(String)
165
+ raise ArgumentError, _("The argument 'code_string' must be a String, got %{type}") % { type: code_string.class }
166
+ end
167
+ internal_evaluator.parse_string(code_string, source_file)
168
+ end
169
+
170
+ # Parses and validates a puppet language file and returns an instance of Puppet::Pops::Model::Program on success.
171
+ # If the content is not valid an error is raised.
172
+ #
173
+ # @param file [String] a file with puppet language content to parse and validate
174
+ # @return [Puppet::Pops::Model::Program] returns a `Program` instance on success
175
+ #
176
+ def parse_file(file)
177
+ unless file.is_a?(String)
178
+ raise ArgumentError, _("The argument 'file' must be a String, got %{type}") % { type: puppet_code.class }
179
+ end
180
+ internal_evaluator.parse_file(file)
181
+ end
182
+
183
+ # Parses a puppet data type given in String format and returns that type, or raises an error.
184
+ # A type is needed in calls to `new` to create an instance of the data type, or to perform type checking
185
+ # of values - typically using `type.instance?(obj)` to check if `obj` is an instance of the type.
186
+ #
187
+ # @example Verify if obj is an instance of a data type
188
+ # # evaluates to true
189
+ # pal.type('Enum[red, blue]').instance?("blue")
190
+ #
191
+ # @example Create an instance of a data type
192
+ # # using an already create type
193
+ # t = pal.type('Car')
194
+ # pal.create(t, 'color' => 'black', 'make' => 't-ford')
195
+ #
196
+ # # letting 'new_object' parse the type from a string
197
+ # pal.create('Car', 'color' => 'black', 'make' => 't-ford')
198
+ #
199
+ # @param type_string [String] a puppet language data type
200
+ # @return [Puppet::Pops::Types::PAnyType] the data type
201
+ #
202
+ def type(type_string)
203
+ Puppet::Pops::Types::TypeParser.singleton.parse(type_string)
204
+ end
205
+
206
+ # Creates a new instance of a given data type.
207
+ # @param data_type [String, Puppet::Pops::Types::PAnyType] the data type as a data type or in String form.
208
+ # @param arguments [Object] one or more arguments to the called `new` function
209
+ # @return [Object] an instance of the given data type,
210
+ # or raises an error if it was not possible to parse data type or create an instance.
211
+ #
212
+ def create(data_type, *arguments)
213
+ t = data_type.is_a?(String) ? type(data_type) : data_type
214
+ unless t.is_a?(Puppet::Pops::Types::PAnyType)
215
+ raise ArgumentError, _("Given data_type value is not a data type, got '%{type}'") % {type: t.class}
216
+ end
217
+ call_function('new', t, *arguments)
218
+ end
219
+
220
+ protected
221
+
222
+ def list_loadable_kind(kind, filter_regex = nil, error_collector = nil)
223
+ loader = internal_compiler.loaders.private_environment_loader
224
+ if filter_regex.nil?
225
+ loader.discover(kind, error_collector)
226
+ else
227
+ loader.discover(kind, error_collector) {|f| f.name =~ filter_regex }
228
+ end
229
+ end
230
+
231
+ private
232
+
233
+ def topscope
234
+ internal_compiler.topscope
235
+ end
236
+ end
237
+
238
+ class ScriptCompiler < Compiler
239
+ # Returns the signature of the given plan name
240
+ # @param plan_name [String] the name of the plan to get the signature of
241
+ # @return [Puppet::Pal::PlanSignature, nil] returns a PlanSignature, or nil if plan is not found
242
+ #
243
+ def plan_signature(plan_name)
244
+ loader = internal_compiler.loaders.private_environment_loader
245
+ if func = loader.load(:plan, plan_name)
246
+ return PlanSignature.new(func)
247
+ end
248
+ # Could not find plan
249
+ nil
250
+ end
251
+
252
+ # Returns an array of TypedName objects for all plans, optionally filtered by a regular expression.
253
+ # The returned array has more information than just the leaf name - the typical thing is to just get
254
+ # the name as showing the following example.
255
+ #
256
+ # Errors that occur during plan discovery will either be logged as warnings or collected by the optional
257
+ # `error_collector` array. When provided, it will receive {Puppet::DataTypes::Error} instances describing
258
+ # each error in detail and no warnings will be logged.
259
+ #
260
+ # @example getting the names of all plans
261
+ # compiler.list_plans.map {|tn| tn.name }
262
+ #
263
+ # @param filter_regex [Regexp] an optional regexp that filters based on name (matching names are included in the result)
264
+ # @param error_collector [Array<Puppet::DataTypes::Error>] an optional array that will receive errors during load
265
+ # @return [Array<Puppet::Pops::Loader::TypedName>] an array of typed names
266
+ #
267
+ def list_plans(filter_regex = nil, error_collector = nil)
268
+ list_loadable_kind(:plan, filter_regex, error_collector)
269
+ end
270
+
271
+ # Returns the signature callable of the given task (the arguments it accepts, and the data type it returns)
272
+ # @param task_name [String] the name of the task to get the signature of
273
+ # @return [Puppet::Pal::TaskSignature, nil] returns a TaskSignature, or nil if task is not found
274
+ #
275
+ def task_signature(task_name)
276
+ loader = internal_compiler.loaders.private_environment_loader
277
+ if task = loader.load(:task, task_name)
278
+ return TaskSignature.new(task)
279
+ end
280
+ # Could not find task
281
+ nil
282
+ end
283
+
284
+ # Returns an array of TypedName objects for all tasks, optionally filtered by a regular expression.
285
+ # The returned array has more information than just the leaf name - the typical thing is to just get
286
+ # the name as showing the following example.
287
+ #
288
+ # @example getting the names of all tasks
289
+ # compiler.list_tasks.map {|tn| tn.name }
290
+ #
291
+ # Errors that occur during task discovery will either be logged as warnings or collected by the optional
292
+ # `error_collector` array. When provided, it will receive {Puppet::DataTypes::Error} instances describing
293
+ # each error in detail and no warnings will be logged.
294
+ #
295
+ # @param filter_regex [Regexp] an optional regexp that filters based on name (matching names are included in the result)
296
+ # @param error_collector [Array<Puppet::DataTypes::Error>] an optional array that will receive errors during load
297
+ # @return [Array<Puppet::Pops::Loader::TypedName>] an array of typed names
298
+ #
299
+ def list_tasks(filter_regex = nil, error_collector = nil)
300
+ list_loadable_kind(:task, filter_regex, error_collector)
301
+ end
302
+ end
303
+
304
+ # A FunctionSignature is returned from `function_signature`. Its purpose is to answer questions about the function's parameters
305
+ # and if it can be called with a set of parameters.
306
+ #
307
+ # It is also possible to get an array of puppet Callable data type where each callable describes one possible way
308
+ # the function can be called.
309
+ #
310
+ # @api public
311
+ #
312
+ class FunctionSignature
313
+ # @api private
314
+ def initialize(function_class)
315
+ @func = function_class
316
+ end
317
+
318
+ # Returns true if the function can be called with the given arguments and false otherwise.
319
+ # If the function is not callable, and a code block is given, it is given a formatted error message that describes
320
+ # the type mismatch. That error message can be quite complex if the function has multiple dispatch depending on
321
+ # given types.
322
+ #
323
+ # @param args [Array] The arguments as given to the function call
324
+ # @param callable [Proc, nil] An optional ruby Proc or puppet lambda given to the function
325
+ # @yield [String] a formatted error message describing a type mismatch if the function is not callable with given args + block
326
+ # @return [Boolean] true if the function can be called with given args + block, and false otherwise
327
+ # @api public
328
+ #
329
+ def callable_with?(args, callable=nil)
330
+ signatures = @func.dispatcher.to_type
331
+ callables = signatures.is_a?(Puppet::Pops::Types::PVariantType) ? signatures.types : [signatures]
332
+
333
+ return true if callables.any? {|t| t.callable_with?(args) }
334
+ return false unless block_given?
335
+ args_type = Puppet::Pops::Types::TypeCalculator.singleton.infer_set(callable.nil? ? args : args + [callable])
336
+ error_message = Puppet::Pops::Types::TypeMismatchDescriber.describe_signatures(@func.name, @func.signatures, args_type)
337
+ yield error_message
338
+ false
339
+ end
340
+
341
+ # Returns an array of Callable puppet data type
342
+ # @return [Array<Puppet::Pops::Types::PCallableType] one callable per way the function can be called
343
+ #
344
+ # @api public
345
+ #
346
+ def callables
347
+ signatures = @func.dispatcher.to_type
348
+ signatures.is_a?(Puppet::Pops::Types::PVariantType) ? signatures.types : [signatures]
349
+ end
350
+ end
351
+
352
+ # A TaskSignature is returned from `task_signature`. Its purpose is to answer questions about the task's parameters
353
+ # and if it can be run/called with a hash of named parameters.
354
+ #
355
+ class TaskSignature
356
+ def initialize(task)
357
+ @task = task
358
+ end
359
+
360
+ # Returns whether or not the given arguments are acceptable when running the task.
361
+ # In addition to returning the boolean outcome, if a block is given, it is called with a string of formatted
362
+ # error messages that describes the difference between what was given and what is expected. The error message may
363
+ # have multiple lines of text, and each line is indented one space.
364
+ #
365
+ # @param args_hash [Hash] a hash mapping parameter names to argument values
366
+ # @yieldparam [String] a formatted error message if a type mismatch occurs that explains the mismatch
367
+ # @return [Boolean] if the given arguments are acceptable when running the task
368
+ #
369
+ def runnable_with?(args_hash)
370
+ params = @task.parameters
371
+ params_type = if params.nil?
372
+ T_GENERIC_TASK_HASH
373
+ else
374
+ key_to_type = {}
375
+ @task.parameters.each_pair { |k, v| key_to_type[k] = v['type'] }
376
+ Puppet::Pops::Types::TypeFactory.struct(key_to_type)
377
+ end
378
+ return true if params_type.instance?(args_hash)
379
+
380
+ if block_given?
381
+ tm = Puppet::Pops::Types::TypeMismatchDescriber.singleton
382
+ error = if params.nil?
383
+ tm.describe_mismatch('', params_type, Puppet::Pops::Types::TypeCalculator.infer_set(args_hash))
384
+ else
385
+ tm.describe_struct_signature(params_type, args_hash).flatten.map {|e| e.format }.join("\n")
386
+ end
387
+ yield "Task #{@task.name}:\n#{error}"
388
+ end
389
+ false
390
+ end
391
+
392
+ # Returns the Task instance as a hash
393
+ #
394
+ # @return [Hash{String=>Object}] the hash representation of the task
395
+ def task_hash
396
+ @task._pcore_init_hash
397
+ end
398
+
399
+ # Returns the Task instance which can be further explored. It contains all meta-data defined for
400
+ # the task such as the description, parameters, output, etc.
401
+ #
402
+ # @return [Puppet::Pops::Types::PuppetObject] An instance of a dynamically created Task class
403
+ def task
404
+ @task
405
+ end
406
+ end
407
+
408
+ # A PlanSignature is returned from `plan_signature`. Its purpose is to answer questions about the plans's parameters
409
+ # and if it can be called with a hash of named parameters.
410
+ #
411
+ # @api public
412
+ #
413
+ class PlanSignature
414
+ def initialize(plan_function)
415
+ @plan_func = plan_function
416
+ end
417
+
418
+ # Returns true or false depending on if the given PlanSignature is callable with a set of named arguments or not
419
+ # In addition to returning the boolean outcome, if a block is given, it is called with a string of formatted
420
+ # error messages that describes the difference between what was given and what is expected. The error message may
421
+ # have multiple lines of text, and each line is indented one space.
422
+ #
423
+ # @example Checking if signature is acceptable
424
+ #
425
+ # signature = pal.plan_signature('myplan')
426
+ # signature.callable_with?({x => 10}) { |errors| raise ArgumentError("Ooops: given arguments does not match\n#{errors}") }
427
+ #
428
+ # @api public
429
+ #
430
+ def callable_with?(args_hash)
431
+ dispatcher = @plan_func.class.dispatcher.dispatchers[0]
432
+
433
+ param_scope = {}
434
+ # Assign all non-nil values, even those that represent non-existent parameters.
435
+ args_hash.each { |k, v| param_scope[k] = v unless v.nil? }
436
+ dispatcher.parameters.each do |p|
437
+ name = p.name
438
+ arg = args_hash[name]
439
+ if arg.nil?
440
+ # Arg either wasn't given, or it was undef
441
+ if p.value.nil?
442
+ # No default. Assign nil if the args_hash included it
443
+ param_scope[name] = nil if args_hash.include?(name)
444
+ else
445
+ # parameter does not have a default value, it will be assigned its default when being called
446
+ # we assume that the default value is of the correct type and therefore simply skip
447
+ # checking this
448
+ # param_scope[name] = param_scope.evaluate(name, p.value, closure_scope, @evaluator)
449
+ end
450
+ end
451
+ end
452
+
453
+ errors = Puppet::Pops::Types::TypeMismatchDescriber.singleton.describe_struct_signature(dispatcher.params_struct, param_scope).flatten
454
+ return true if errors.empty?
455
+ if block_given?
456
+ yield errors.map {|e| e.format }.join("\n")
457
+ end
458
+ false
459
+ end
460
+
461
+ # Returns a PStructType describing the parameters as a puppet Struct data type
462
+ # Note that a `to_s` on the returned structure will result in a human readable Struct datatype as a
463
+ # description of what a plan expects.
464
+ #
465
+ # @return [Puppet::Pops::Types::PStructType] a struct data type describing the parameters and their types
466
+ #
467
+ # @api public
468
+ #
469
+ def params_type
470
+ dispatcher = @plan_func.class.dispatcher.dispatchers[0]
471
+ dispatcher.params_struct
472
+ end
473
+ end
474
+
475
+ # Defines a context in which multiple operations in an env with a script compiler can be performed in a given block.
476
+ # The calls that takes place to PAL inside of the given block are all with the same instance of the compiler.
477
+ # The parameter `configured_by_env` makes it possible to either use the configuration in the environment, or specify
478
+ # `manifest_file` or `code_string` manually. If neither is given, an empty `code_string` is used.
479
+ #
480
+ # @example define a script compiler without any initial logic
481
+ # pal.with_script_compiler do | compiler |
482
+ # # do things with compiler
483
+ # end
484
+ #
485
+ # @example define a script compiler with a code_string containing initial logic
486
+ # pal.with_script_compiler(code_string: '$myglobal_var = 42') do | compiler |
487
+ # # do things with compiler
488
+ # end
489
+ #
490
+ # @param configured_by_env [Boolean] when true the environment's settings are used, otherwise the given `manifest_file` or `code_string`
491
+ # @param manifest_file [String] a Puppet Language file to load and evaluate before calling the given block, mutually exclusive with `code_string`
492
+ # @param code_string [String] a Puppet Language source string to load and evaluate before calling the given block, mutually exclusive with `manifest_file`
493
+ # @param facts [Hash] optional map of fact name to fact value - if not given will initialize the facts (which is a slow operation)
494
+ # If given at the environment level, the facts given here are merged with higher priority.
495
+ # @param variables [Hash] optional map of fully qualified variable name to value. If given at the environment level, the variables
496
+ # given here are merged with higher priority.
497
+ # @param block [Proc] the block performing operations on compiler
498
+ # @return [Object] what the block returns
499
+ # @yieldparam [Puppet::Pal::ScriptCompiler] compiler, a ScriptCompiler to perform operations on.
500
+ #
501
+ def self.with_script_compiler(
502
+ configured_by_env: false,
503
+ manifest_file: nil,
504
+ code_string: nil,
505
+ facts: nil,
506
+ variables: nil,
507
+ &block
508
+ )
509
+ # TRANSLATORS: do not translate variable name strings in these assertions
510
+ assert_mutually_exclusive(manifest_file, code_string, 'manifest_file', 'code_string')
511
+ assert_non_empty_string(manifest_file, 'manifest_file', true)
512
+ assert_non_empty_string(code_string, 'code_string', true)
513
+ assert_type(T_BOOLEAN, configured_by_env, "configured_by_env", false)
514
+
515
+ if configured_by_env
516
+ unless manifest_file.nil? && code_string.nil?
517
+ # TRANSLATORS: do not translate the variable names in this error message
518
+ raise ArgumentError, _("manifest_file or code_string cannot be given when configured_by_env is true")
519
+ end
520
+ # Use the manifest setting
521
+ manifest_file = Puppet[:manifest]
522
+ else
523
+ # An "undef" code_string is the only way to override Puppet[:manifest] & Puppet[:code] settings since an
524
+ # empty string is taken as Puppet[:code] not being set.
525
+ #
526
+ if manifest_file.nil? && code_string.nil?
527
+ code_string = 'undef'
528
+ end
529
+ end
530
+
531
+ Puppet[:tasks] = true
532
+ # After the assertions, if code_string is non nil - it has the highest precedence
533
+ Puppet[:code] = code_string unless code_string.nil?
534
+
535
+ # If manifest_file is nil, the #main method will use the env configured manifest
536
+ # to do things in the block while a Script Compiler is in effect
537
+ main(manifest_file, facts, variables, &block)
538
+ end
539
+
540
+ # Evaluates a Puppet Language script string.
541
+ # @param code_string [String] a snippet of Puppet Language source code
542
+ # @return [Object] what the Puppet Language code_string evaluates to
543
+ # @deprecated Use {#with_script_compiler} and then evaluate_string on the given compiler - to be removed in 1.0 version
544
+ #
545
+ def self.evaluate_script_string(code_string)
546
+ # prevent the default loading of Puppet[:manifest] which is the environment's manifest-dir by default settings
547
+ # by setting code_string to 'undef'
548
+ with_script_compiler do |compiler|
549
+ compiler.evaluate_string(code_string)
550
+ end
551
+ end
552
+
553
+ # Evaluates a Puppet Language script (.pp) file.
554
+ # @param manifest_file [String] a file with Puppet Language source code
555
+ # @return [Object] what the Puppet Language manifest_file contents evaluates to
556
+ # @deprecated Use {#with_script_compiler} and then evaluate_file on the given compiler - to be removed in 1.0 version
557
+ #
558
+ def self.evaluate_script_manifest(manifest_file)
559
+ with_script_compiler do |compiler|
560
+ compiler.evaluate_file(manifest_file)
561
+ end
562
+ end
563
+
564
+
565
+ # Defines the context in which to perform puppet operations (evaluation, etc)
566
+ # The code to evaluate in this context is given in a block.
567
+ #
568
+ # @param env_name [String] a name to use for the temporary environment - this only shows up in errors
569
+ # @param modulepath [Array<String>] an array of directory paths containing Puppet modules, may be empty, defaults to empty array
570
+ # @param settings_hash [Hash] a hash of settings - currently not used for anything, defaults to empty hash
571
+ # @param facts [Hash] optional map of fact name to fact value - if not given will initialize the facts (which is a slow operation)
572
+ # @param variables [Hash] optional map of fully qualified variable name to value
573
+ # @return [Object] returns what the given block returns
574
+ # @yieldparam [Puppet::Pal] context, a context that responds to Puppet::Pal methods
575
+ #
576
+ def self.in_tmp_environment(env_name,
577
+ modulepath: [],
578
+ settings_hash: {},
579
+ facts: nil,
580
+ variables: {},
581
+ &block
582
+ )
583
+ assert_non_empty_string(env_name, _("temporary environment name"))
584
+ # TRANSLATORS: do not translate variable name string in these assertions
585
+ assert_optionally_empty_array(modulepath, 'modulepath')
586
+
587
+ unless block_given?
588
+ raise ArgumentError, _("A block must be given to 'in_tmp_environment'") # TRANSLATORS 'in_tmp_environment' is a name, do not translate
589
+ end
590
+
591
+ env = Puppet::Node::Environment.create(env_name, modulepath)
592
+
593
+ in_environment_context(
594
+ Puppet::Environments::Static.new(env), # The tmp env is the only known env
595
+ env, facts, variables, &block
596
+ )
597
+ end
598
+
599
+ # Defines the context in which to perform puppet operations (evaluation, etc)
600
+ # The code to evaluate in this context is given in a block.
601
+ #
602
+ # The name of an environment (env_name) is always given. The location of that environment on disk
603
+ # is then either constructed by:
604
+ # * searching a given envpath where name is a child of a directory on that path, or
605
+ # * it is the directory given in env_dir (which must exist).
606
+ #
607
+ # The env_dir and envpath options are mutually exclusive.
608
+ #
609
+ # @param env_name [String] the name of an existing environment
610
+ # @param modulepath [Array<String>] an array of directory paths containing Puppet modules, overrides the modulepath of an existing env.
611
+ # Defaults to `{env_dir}/modules` if `env_dir` is given,
612
+ # @param pre_modulepath [Array<String>] like modulepath, but is prepended to the modulepath
613
+ # @param post_modulepath [Array<String>] like modulepath, but is appended to the modulepath
614
+ # @param settings_hash [Hash] a hash of settings - currently not used for anything, defaults to empty hash
615
+ # @param env_dir [String] a reference to a directory being the named environment (mutually exclusive with `envpath`)
616
+ # @param envpath [String] a path of directories in which there are environments to search for `env_name` (mutually exclusive with `env_dir`).
617
+ # Should be a single directory, or several directories separated with platform specific `File::PATH_SEPARATOR` character.
618
+ # @param facts [Hash] optional map of fact name to fact value - if not given will initialize the facts (which is a slow operation)
619
+ # @param variables [Hash] optional map of fully qualified variable name to value
620
+ # @return [Object] returns what the given block returns
621
+ # @yieldparam [Puppet::Pal] context, a context that responds to Puppet::Pal methods
622
+ #
623
+ def self.in_environment(env_name,
624
+ modulepath: nil,
625
+ pre_modulepath: [],
626
+ post_modulepath: [],
627
+ settings_hash: {},
628
+ env_dir: nil,
629
+ envpath: nil,
630
+ facts: nil,
631
+ variables: {},
632
+ &block
633
+ )
634
+ # TRANSLATORS terms in the assertions below are names of terms in code
635
+ assert_non_empty_string(env_name, 'env_name')
636
+ assert_optionally_empty_array(modulepath, 'modulepath', true)
637
+ assert_optionally_empty_array(pre_modulepath, 'pre_modulepath', false)
638
+ assert_optionally_empty_array(post_modulepath, 'post_modulepath', false)
639
+ assert_mutually_exclusive(env_dir, envpath, 'env_dir', 'envpath')
640
+
641
+ unless block_given?
642
+ raise ArgumentError, _("A block must be given to 'in_environment'") # TRANSLATORS 'in_environment' is a name, do not translate
643
+ end
644
+
645
+ if env_dir
646
+ unless Puppet::FileSystem.exist?(env_dir)
647
+ raise ArgumentError, _("The environment directory '%{env_dir}' does not exist") % { env_dir: env_dir }
648
+ end
649
+
650
+ # a nil modulepath for env_dir means it should use its ./modules directory
651
+ mid_modulepath = modulepath.nil? ? [Puppet::FileSystem.expand_path(File.join(env_dir, 'modules'))] : modulepath
652
+
653
+ env = Puppet::Node::Environment.create(env_name, pre_modulepath + mid_modulepath + post_modulepath)
654
+ environments = Puppet::Environments::StaticDirectory.new(env_name, env_dir, env) # The env being used is the only one...
655
+ else
656
+ assert_non_empty_string(envpath, 'envpath')
657
+
658
+ # The environment is resolved against the envpath. This is setup without a basemodulepath
659
+ # The modulepath defaults to the 'modulepath' in the found env when "Directories" is used
660
+ #
661
+ if envpath.is_a?(String) && envpath.include?(File::PATH_SEPARATOR)
662
+ # potentially more than one directory to search
663
+ env_loaders = Puppet::Environments::Directories.from_path(envpath, [])
664
+ environments = Puppet::Environments::Combined.new(*env_loaders)
665
+ else
666
+ environments = Puppet::Environments::Directories.new(envpath, [])
667
+ end
668
+ env = environments.get(env_name)
669
+ if env.nil?
670
+ raise ArgumentError, _("No directory found for the environment '%{env_name}' on the path '%{envpath}'") % { env_name: env_name, envpath: envpath }
671
+ end
672
+ # A given modulepath should override the default
673
+ mid_modulepath = modulepath.nil? ? env.modulepath : modulepath
674
+ env_path = env.configuration.path_to_env
675
+ env = env.override_with(:modulepath => pre_modulepath + mid_modulepath + post_modulepath)
676
+ # must configure this in case logic looks up the env by name again (otherwise the looked up env does
677
+ # not have the same effective modulepath).
678
+ environments = Puppet::Environments::StaticDirectory.new(env_name, env_path, env) # The env being used is the only one...
679
+ end
680
+ in_environment_context(environments, env, facts, variables, &block)
681
+ end
682
+
683
+ private
684
+
685
+ # Prepares the puppet context with pal information - and delegates to the block
686
+ # No set up is performed at this step - it is delayed until it is known what the
687
+ # operation is going to be (for example - using a ScriptCompiler).
688
+ #
689
+ def self.in_environment_context(environments, env, facts, variables, &block)
690
+ # Create a default node to use (may be overridden later)
691
+ node = Puppet::Node.new(Puppet[:node_name_value], :environment => env)
692
+
693
+ Puppet.override(
694
+ environments: environments, # The env being used is the only one...
695
+ pal_env: env, # provide as convenience
696
+ pal_current_node: node, # to allow it to be picked up instead of created
697
+ pal_variables: variables, # common set of variables across several inner contexts
698
+ pal_facts: facts # common set of facts across several inner contexts (or nil)
699
+ ) do
700
+ # DELAY: prepare_node_facts(node, facts)
701
+ return block.call(self)
702
+ end
703
+ end
704
+
705
+ # Prepares the node for use by giving it node_facts (if given)
706
+ # If a hash of facts values is given, then the operation of creating a node with facts is much
707
+ # speeded up (as getting a fresh set of facts is avoided in a later step).
708
+ #
709
+ def self.prepare_node_facts(node, facts)
710
+ # Prepare the node with facts if it does not already have them
711
+ if node.facts.nil?
712
+ node_facts = facts.nil? ? nil : Puppet::Node::Facts.new(Puppet[:node_name_value], facts)
713
+ node.fact_merge(node_facts)
714
+ # Add server facts so $server_facts[environment] exists when doing a puppet script
715
+ # SCRIPT TODO: May be needed when running scripts under orchestrator. Leave it for now.
716
+ #
717
+ node.add_server_facts({})
718
+ end
719
+ end
720
+
721
+ def self.add_variables(scope, variables)
722
+ return if variables.nil?
723
+ unless variables.is_a?(Hash)
724
+ raise ArgumentError, _("Given variables must be a hash, got %{type}") % { type: variables.class }
725
+ end
726
+
727
+ rich_data_t = Puppet::Pops::Types::TypeFactory.rich_data
728
+ variables.each_pair do |k,v|
729
+ unless k =~ Puppet::Pops::Patterns::VAR_NAME
730
+ raise ArgumentError, _("Given variable '%{varname}' has illegal name") % { varname: k }
731
+ end
732
+
733
+ unless rich_data_t.instance?(v)
734
+ raise ArgumentError, _("Given value for '%{varname}' has illegal type - got: %{type}") % { varname: k, type: v.class }
735
+ end
736
+
737
+ scope.setvar(k, v)
738
+ end
739
+ end
740
+
741
+ # The main routine for script compiler
742
+ # Picks up information from the puppet context and configures a script compiler which is given to
743
+ # the provided block
744
+ #
745
+ def self.main(manifest, facts, variables)
746
+ # Configure the load path
747
+ env = Puppet.lookup(:pal_env)
748
+ env.each_plugin_directory do |dir|
749
+ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
750
+ end
751
+
752
+ # Puppet requires Facter, which initializes its lookup paths. Reset Facter to
753
+ # pickup the new $LOAD_PATH.
754
+ Facter.reset
755
+
756
+ node = Puppet.lookup(:pal_current_node)
757
+ pal_facts = Puppet.lookup(:pal_facts)
758
+ pal_variables = Puppet.lookup(:pal_variables)
759
+
760
+ overrides = {}
761
+ unless facts.nil? || facts.empty?
762
+ pal_facts = pal_facts.merge(facts)
763
+ overrides[:pal_facts] = pal_facts
764
+ end
765
+ unless variables.nil? || variables.empty?
766
+ pal_variables = pal_variables.merge(variables)
767
+ overrides[:pal_variables] = pal_variables
768
+ end
769
+
770
+ prepare_node_facts(node, pal_facts)
771
+
772
+ configured_environment = node.environment || Puppet.lookup(:current_environment)
773
+
774
+ apply_environment = manifest ?
775
+ configured_environment.override_with(:manifest => manifest) :
776
+ configured_environment
777
+
778
+ # Modify the node descriptor to use the special apply_environment.
779
+ # It is based on the actual environment from the node, or the locally
780
+ # configured environment if the node does not specify one.
781
+ # If a manifest file is passed on the command line, it overrides
782
+ # the :manifest setting of the apply_environment.
783
+ node.environment = apply_environment
784
+
785
+ # TRANSLATORS, the string "For puppet PAL" is not user facing
786
+ Puppet.override({:current_environment => apply_environment}, "For puppet PAL") do
787
+ begin
788
+ # support the following features when evaluating puppet code
789
+ # * $facts with facts from host running the script
790
+ # * $settings with 'settings::*' namespace populated, and '$settings::all_local' hash
791
+ # * $trusted as setup when using puppet apply
792
+ # * an environment
793
+ #
794
+
795
+ # fixup trusted information
796
+ node.sanitize()
797
+
798
+ compiler = Puppet::Parser::ScriptCompiler.new(node.environment, node.name)
799
+ topscope = compiler.topscope
800
+
801
+ # When scripting the trusted data are always local, but set them anyway
802
+ topscope.set_trusted(node.trusted_data)
803
+
804
+ # Server facts are always about the local node's version etc.
805
+ topscope.set_server_facts(node.server_facts)
806
+
807
+ # Set $facts for the node running the script
808
+ facts_hash = node.facts.nil? ? {} : node.facts.values
809
+ topscope.set_facts(facts_hash)
810
+
811
+ # create the $settings:: variables
812
+ topscope.merge_settings(node.environment.name, false)
813
+
814
+ add_variables(topscope, pal_variables)
815
+
816
+ # compiler.compile(&block)
817
+ compiler.compile do | internal_compiler |
818
+ # wrap the internal compiler to prevent it from leaking in the PAL API
819
+ if block_given?
820
+ script_compiler = ScriptCompiler.new(internal_compiler)
821
+
822
+ # Make compiler available to Puppet#lookup
823
+ overrides[:pal_script_compiler] = script_compiler
824
+ Puppet.override(overrides, "PAL::with_script_compiler") do # TRANSLATORS: Do not translate, symbolic name
825
+ yield(script_compiler)
826
+ end
827
+ end
828
+ end
829
+
830
+ rescue Puppet::ParseErrorWithIssue, Puppet::Error
831
+ # already logged and handled by the compiler for these two cases
832
+ raise
833
+
834
+ rescue => detail
835
+ Puppet.log_exception(detail)
836
+ raise
837
+ end
838
+ end
839
+ end
840
+
841
+ T_STRING = Puppet::Pops::Types::PStringType::NON_EMPTY
842
+ T_STRING_ARRAY = Puppet::Pops::Types::TypeFactory.array_of(T_STRING)
843
+ T_ANY_ARRAY = Puppet::Pops::Types::TypeFactory.array_of_any
844
+ T_BOOLEAN = Puppet::Pops::Types::PBooleanType::DEFAULT
845
+
846
+ T_GENERIC_TASK_HASH = Puppet::Pops::Types::TypeFactory.hash_kv(
847
+ Puppet::Pops::Types::TypeFactory.pattern(/\A[a-z][a-z0-9_]*\z/), Puppet::Pops::Types::TypeFactory.data)
848
+
849
+ def self.assert_type(type, value, what, allow_nil=false)
850
+ Puppet::Pops::Types::TypeAsserter.assert_instance_of(nil, type, value, allow_nil) { _('Puppet Pal: %{what}') % {what: what} }
851
+ end
852
+
853
+ def self.assert_non_empty_string(s, what, allow_nil=false)
854
+ assert_type(T_STRING, s, what, allow_nil)
855
+ end
856
+
857
+ def self.assert_optionally_empty_array(a, what, allow_nil=false)
858
+ assert_type(T_STRING_ARRAY, a, what, allow_nil)
859
+ end
860
+
861
+ def self.assert_mutually_exclusive(a, b, a_term, b_term)
862
+ if a && b
863
+ raise ArgumentError, _("Cannot use '%{a_term}' and '%{b_term}' at the same time") % { a_term: a_term, b_term: b_term }
864
+ end
865
+ end
866
+
867
+ def self.assert_block_given(block)
868
+ if block.nil?
869
+ raise ArgumentError, _("A block must be given")
870
+ end
871
+ end
872
+ end
873
+ end
874
+