puppet 3.2.4 → 3.3.0.rc2

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 (562) hide show
  1. data/COMMITTERS.md +101 -42
  2. data/Gemfile +15 -4
  3. data/README.md +5 -1
  4. data/README_DEVELOPER.md +117 -54
  5. data/Rakefile +4 -0
  6. data/ext/build_defaults.yaml +3 -2
  7. data/ext/debian/puppet-common.manpages +33 -1
  8. data/ext/gentoo/init.d/puppet +1 -1
  9. data/ext/gentoo/init.d/puppetmaster +1 -1
  10. data/ext/redhat/puppet.spec.erb +0 -1
  11. data/install.rb +2 -1
  12. data/lib/hiera/backend/puppet_backend.rb +1 -1
  13. data/lib/puppet/application.rb +10 -9
  14. data/lib/puppet/application/agent.rb +87 -93
  15. data/lib/puppet/application/apply.rb +0 -2
  16. data/lib/puppet/application/device.rb +3 -3
  17. data/lib/puppet/application/kick.rb +2 -2
  18. data/lib/puppet/application/master.rb +41 -19
  19. data/lib/puppet/application/queue.rb +5 -3
  20. data/lib/puppet/bindings.rb +147 -0
  21. data/lib/puppet/configurer.rb +25 -15
  22. data/lib/puppet/configurer/fact_handler.rb +2 -9
  23. data/lib/puppet/daemon.rb +44 -33
  24. data/lib/puppet/defaults.rb +57 -26
  25. data/lib/puppet/error.rb +1 -1
  26. data/lib/puppet/external/dot.rb +2 -2
  27. data/lib/puppet/external/nagios/base.rb +1 -6
  28. data/lib/puppet/external/pson/common.rb +2 -2
  29. data/lib/puppet/external/pson/pure/generator.rb +2 -2
  30. data/lib/puppet/external/pson/pure/parser.rb +1 -1
  31. data/lib/puppet/face/ca.rb +1 -1
  32. data/lib/puppet/face/config.rb +1 -1
  33. data/lib/puppet/face/help.rb +2 -2
  34. data/lib/puppet/face/module/list.rb +2 -2
  35. data/lib/puppet/feature/rails.rb +1 -1
  36. data/lib/puppet/file_bucket/dipper.rb +0 -1
  37. data/lib/puppet/file_serving/base.rb +1 -1
  38. data/lib/puppet/file_serving/configuration/parser.rb +20 -14
  39. data/lib/puppet/forge.rb +0 -32
  40. data/lib/puppet/forge/cache.rb +1 -1
  41. data/lib/puppet/forge/errors.rb +3 -3
  42. data/lib/puppet/forge/repository.rb +7 -42
  43. data/lib/puppet/graph.rb +11 -0
  44. data/lib/puppet/graph/key.rb +26 -0
  45. data/lib/puppet/graph/prioritizer.rb +29 -0
  46. data/lib/puppet/graph/random_prioritizer.rb +16 -0
  47. data/lib/puppet/{rb_tree_map.rb → graph/rb_tree_map.rb} +3 -3
  48. data/lib/puppet/graph/relationship_graph.rb +246 -0
  49. data/lib/puppet/graph/sequential_prioritizer.rb +31 -0
  50. data/lib/puppet/{simple_graph.rb → graph/simple_graph.rb} +22 -3
  51. data/lib/puppet/graph/title_hash_prioritizer.rb +16 -0
  52. data/lib/puppet/indirector.rb +2 -2
  53. data/lib/puppet/indirector/catalog/compiler.rb +10 -7
  54. data/lib/puppet/indirector/catalog/static_compiler.rb +50 -0
  55. data/lib/puppet/indirector/certificate/rest.rb +1 -1
  56. data/lib/puppet/indirector/exec.rb +1 -1
  57. data/lib/puppet/indirector/facts/facter.rb +2 -2
  58. data/lib/puppet/indirector/facts/inventory_active_record.rb +0 -1
  59. data/lib/puppet/indirector/facts/network_device.rb +1 -1
  60. data/lib/puppet/indirector/file_bucket_file/file.rb +0 -1
  61. data/lib/puppet/indirector/indirection.rb +2 -2
  62. data/lib/puppet/indirector/memory.rb +9 -0
  63. data/lib/puppet/indirector/node/ldap.rb +2 -4
  64. data/lib/puppet/indirector/report/processor.rb +1 -2
  65. data/lib/puppet/indirector/report/rest.rb +1 -1
  66. data/lib/puppet/indirector/request.rb +32 -10
  67. data/lib/puppet/indirector/resource/rest.rb +1 -1
  68. data/lib/puppet/indirector/resource_type/parser.rb +31 -12
  69. data/lib/puppet/interface.rb +1 -1
  70. data/lib/puppet/interface/documentation.rb +7 -11
  71. data/lib/puppet/interface/option.rb +1 -1
  72. data/lib/puppet/interface/option_builder.rb +1 -1
  73. data/lib/puppet/metatype/manager.rb +2 -2
  74. data/lib/puppet/module.rb +7 -1
  75. data/lib/puppet/module_tool.rb +1 -1
  76. data/lib/puppet/module_tool/applications/application.rb +10 -0
  77. data/lib/puppet/module_tool/applications/installer.rb +6 -3
  78. data/lib/puppet/module_tool/dependency.rb +2 -0
  79. data/lib/puppet/module_tool/errors/upgrader.rb +1 -1
  80. data/lib/puppet/module_tool/metadata.rb +25 -13
  81. data/lib/puppet/module_tool/modulefile.rb +7 -7
  82. data/lib/puppet/module_tool/shared_behaviors.rb +4 -2
  83. data/lib/puppet/module_tool/skeleton.rb +1 -1
  84. data/lib/puppet/module_tool/skeleton/templates/generator/manifests/init.pp.erb +5 -5
  85. data/lib/puppet/module_tool/skeleton/templates/generator/tests/init.pp.erb +5 -4
  86. data/lib/puppet/network/auth_config_parser.rb +3 -0
  87. data/lib/puppet/network/authconfig.rb +0 -1
  88. data/lib/puppet/network/authorization.rb +1 -1
  89. data/lib/puppet/network/authstore.rb +2 -2
  90. data/lib/puppet/network/format_handler.rb +25 -114
  91. data/lib/puppet/network/format_support.rb +106 -0
  92. data/lib/puppet/network/formats.rb +10 -4
  93. data/lib/puppet/network/http/compression.rb +1 -1
  94. data/lib/puppet/network/http/connection.rb +76 -32
  95. data/lib/puppet/network/http/handler.rb +122 -61
  96. data/lib/puppet/network/http/rack/rest.rb +1 -1
  97. data/lib/puppet/network/http/webrick/rest.rb +9 -3
  98. data/lib/puppet/network/http_pool.rb +2 -2
  99. data/lib/puppet/network/resolver.rb +1 -0
  100. data/lib/puppet/network/server.rb +5 -81
  101. data/lib/puppet/node/environment.rb +256 -13
  102. data/lib/puppet/node/facts.rb +28 -2
  103. data/lib/puppet/parameter.rb +27 -18
  104. data/lib/puppet/parameter/boolean.rb +20 -0
  105. data/lib/puppet/parameter/path.rb +1 -1
  106. data/lib/puppet/parameter/value.rb +1 -1
  107. data/lib/puppet/parameter/value_collection.rb +1 -1
  108. data/lib/puppet/parser/ast/arithmetic_operator.rb +8 -0
  109. data/lib/puppet/parser/ast/casestatement.rb +0 -3
  110. data/lib/puppet/parser/ast/lambda.rb +25 -6
  111. data/lib/puppet/parser/ast/leaf.rb +10 -3
  112. data/lib/puppet/parser/ast/nop.rb +1 -1
  113. data/lib/puppet/parser/ast/resource_override.rb +0 -2
  114. data/lib/puppet/parser/compiler.rb +92 -34
  115. data/lib/puppet/parser/files.rb +0 -5
  116. data/lib/puppet/parser/functions/create_resources.rb +23 -46
  117. data/lib/puppet/parser/functions/each.rb +0 -2
  118. data/lib/puppet/parser/functions/extlookup.rb +2 -2
  119. data/lib/puppet/parser/functions/foreach.rb +0 -2
  120. data/lib/puppet/parser/functions/hiera_include.rb +1 -1
  121. data/lib/puppet/parser/functions/lookup.rb +44 -0
  122. data/lib/puppet/parser/functions/slice.rb +1 -1
  123. data/lib/puppet/parser/grammar.ra +0 -1
  124. data/lib/puppet/parser/lexer.rb +0 -1
  125. data/lib/puppet/parser/parser.rb +0 -1
  126. data/lib/puppet/parser/parser_factory.rb +3 -2
  127. data/lib/puppet/parser/parser_support.rb +1 -1
  128. data/lib/puppet/parser/relationship.rb +1 -1
  129. data/lib/puppet/parser/scope.rb +49 -24
  130. data/lib/puppet/parser/type_loader.rb +13 -18
  131. data/lib/puppet/pops.rb +45 -0
  132. data/lib/puppet/pops/adaptable.rb +2 -2
  133. data/lib/puppet/pops/adapters.rb +4 -0
  134. data/lib/puppet/pops/binder/binder.rb +421 -0
  135. data/lib/puppet/pops/binder/binder_issues.rb +142 -0
  136. data/lib/puppet/pops/binder/bindings_checker.rb +217 -0
  137. data/lib/puppet/pops/binder/bindings_composer.rb +241 -0
  138. data/lib/puppet/pops/binder/bindings_factory.rb +847 -0
  139. data/lib/puppet/pops/binder/bindings_label_provider.rb +46 -0
  140. data/lib/puppet/pops/binder/bindings_loader.rb +79 -0
  141. data/lib/puppet/pops/binder/bindings_model.rb +215 -0
  142. data/lib/puppet/pops/binder/bindings_model_dumper.rb +205 -0
  143. data/lib/puppet/pops/binder/bindings_validator_factory.rb +28 -0
  144. data/lib/puppet/pops/binder/config/binder_config.rb +139 -0
  145. data/lib/puppet/pops/binder/config/binder_config_checker.rb +183 -0
  146. data/lib/puppet/pops/binder/config/diagnostic_producer.rb +32 -0
  147. data/lib/puppet/pops/binder/config/issues.rb +106 -0
  148. data/lib/puppet/pops/binder/hiera2.rb +10 -0
  149. data/lib/puppet/pops/binder/hiera2/bindings_provider.rb +148 -0
  150. data/lib/puppet/pops/binder/hiera2/config.rb +69 -0
  151. data/lib/puppet/pops/binder/hiera2/config_checker.rb +68 -0
  152. data/lib/puppet/pops/binder/hiera2/diagnostic_producer.rb +36 -0
  153. data/lib/puppet/pops/binder/hiera2/issues.rb +67 -0
  154. data/lib/puppet/pops/binder/hiera2/json_backend.rb +18 -0
  155. data/lib/puppet/pops/binder/hiera2/yaml_backend.rb +21 -0
  156. data/lib/puppet/pops/binder/injector.rb +688 -0
  157. data/lib/puppet/pops/binder/injector_entry.rb +53 -0
  158. data/lib/puppet/pops/binder/key_factory.rb +61 -0
  159. data/lib/puppet/pops/binder/producers.rb +829 -0
  160. data/lib/puppet/pops/binder/scheme_handler/confdir_hiera_scheme.rb +67 -0
  161. data/lib/puppet/pops/binder/scheme_handler/confdir_scheme.rb +34 -0
  162. data/lib/puppet/pops/binder/scheme_handler/module_hiera_scheme.rb +92 -0
  163. data/lib/puppet/pops/binder/scheme_handler/module_scheme.rb +84 -0
  164. data/lib/puppet/pops/binder/scheme_handler/symbolic_scheme.rb +54 -0
  165. data/lib/puppet/pops/binder/system_bindings.rb +72 -0
  166. data/lib/puppet/pops/issue_reporter.rb +75 -0
  167. data/lib/puppet/pops/issues.rb +9 -5
  168. data/lib/puppet/pops/model/ast_transformer.rb +4 -4
  169. data/lib/puppet/pops/model/ast_tree_dumper.rb +1 -1
  170. data/lib/puppet/pops/model/factory.rb +25 -13
  171. data/lib/puppet/pops/model/model.rb +1 -1
  172. data/lib/puppet/pops/model/tree_dumper.rb +2 -2
  173. data/lib/puppet/pops/parser/egrammar.ra +0 -1
  174. data/lib/puppet/pops/parser/eparser.rb +1 -2
  175. data/lib/puppet/pops/parser/evaluating_parser.rb +162 -0
  176. data/lib/puppet/pops/parser/lexer.rb +8 -6
  177. data/lib/puppet/pops/types/class_loader.rb +118 -0
  178. data/lib/puppet/pops/types/type_calculator.rb +557 -0
  179. data/lib/puppet/pops/types/type_factory.rb +147 -0
  180. data/lib/puppet/pops/types/type_parser.rb +117 -0
  181. data/lib/puppet/pops/types/types.rb +132 -0
  182. data/lib/puppet/pops/validation.rb +146 -17
  183. data/lib/puppet/pops/validation/checker3_1.rb +1 -1
  184. data/lib/puppet/pops/validation/validator_factory_3_1.rb +6 -16
  185. data/lib/puppet/property.rb +3 -3
  186. data/lib/puppet/property/keyvalue.rb +1 -1
  187. data/lib/puppet/provider.rb +2 -2
  188. data/lib/puppet/provider/aixobject.rb +19 -21
  189. data/lib/puppet/provider/augeas/augeas.rb +3 -1
  190. data/lib/puppet/provider/command.rb +2 -2
  191. data/lib/puppet/provider/group/aix.rb +1 -1
  192. data/lib/puppet/provider/group/ldap.rb +1 -1
  193. data/lib/puppet/provider/macauthorization/macauthorization.rb +1 -1
  194. data/lib/puppet/provider/mailalias/aliases.rb +3 -8
  195. data/lib/puppet/provider/mcx/mcxcontent.rb +7 -1
  196. data/lib/puppet/provider/mount.rb +8 -3
  197. data/lib/puppet/provider/nameservice.rb +1 -1
  198. data/lib/puppet/provider/nameservice/directoryservice.rb +5 -5
  199. data/lib/puppet/provider/package/appdmg.rb +1 -1
  200. data/lib/puppet/provider/package/apt.rb +0 -1
  201. data/lib/puppet/provider/package/dpkg.rb +86 -32
  202. data/lib/puppet/provider/package/fink.rb +0 -2
  203. data/lib/puppet/provider/package/freebsd.rb +0 -2
  204. data/lib/puppet/provider/package/openbsd.rb +57 -10
  205. data/lib/puppet/provider/package/opkg.rb +0 -1
  206. data/lib/puppet/provider/package/pacman.rb +0 -1
  207. data/lib/puppet/provider/package/pip.rb +1 -1
  208. data/lib/puppet/provider/package/pkgdmg.rb +17 -6
  209. data/lib/puppet/provider/package/pkgutil.rb +1 -1
  210. data/lib/puppet/provider/package/portage.rb +9 -1
  211. data/lib/puppet/provider/package/ports.rb +2 -2
  212. data/lib/puppet/provider/package/rpm.rb +29 -12
  213. data/lib/puppet/provider/package/rug.rb +1 -1
  214. data/lib/puppet/provider/package/urpmi.rb +11 -15
  215. data/lib/puppet/provider/package/windows/exe_package.rb +1 -1
  216. data/lib/puppet/provider/package/windows/package.rb +1 -26
  217. data/lib/puppet/provider/package/yum.rb +1 -1
  218. data/lib/puppet/provider/package/zypper.rb +22 -3
  219. data/lib/puppet/provider/parsedfile.rb +1 -12
  220. data/lib/puppet/provider/scheduled_task/win32_taskscheduler.rb +1 -1
  221. data/lib/puppet/provider/service/base.rb +1 -1
  222. data/lib/puppet/provider/service/daemontools.rb +3 -3
  223. data/lib/puppet/provider/service/debian.rb +1 -1
  224. data/lib/puppet/provider/service/init.rb +14 -20
  225. data/lib/puppet/provider/service/openrc.rb +3 -1
  226. data/lib/puppet/provider/service/redhat.rb +5 -8
  227. data/lib/puppet/provider/service/runit.rb +3 -2
  228. data/lib/puppet/provider/service/systemd.rb +1 -1
  229. data/lib/puppet/provider/ssh_authorized_key/parsed.rb +1 -1
  230. data/lib/puppet/provider/sshkey/parsed.rb +0 -2
  231. data/lib/puppet/provider/user/aix.rb +25 -12
  232. data/lib/puppet/provider/user/directoryservice.rb +4 -7
  233. data/lib/puppet/provider/user/ldap.rb +0 -1
  234. data/lib/puppet/provider/user/user_role_add.rb +2 -0
  235. data/lib/puppet/provider/user/useradd.rb +1 -1
  236. data/lib/puppet/provider/zone/solaris.rb +1 -2
  237. data/lib/puppet/reference/metaparameter.rb +1 -1
  238. data/lib/puppet/reference/type.rb +1 -1
  239. data/lib/puppet/reports/rrdgraph.rb +1 -1
  240. data/lib/puppet/reports/tagmail.rb +1 -1
  241. data/lib/puppet/resource.rb +16 -4
  242. data/lib/puppet/resource/catalog.rb +111 -173
  243. data/lib/puppet/resource/status.rb +42 -3
  244. data/lib/puppet/resource/type.rb +33 -46
  245. data/lib/puppet/resource/type_collection.rb +19 -15
  246. data/lib/puppet/run.rb +5 -1
  247. data/lib/puppet/scheduler/scheduler.rb +14 -15
  248. data/lib/puppet/settings.rb +78 -41
  249. data/lib/puppet/settings/boolean_setting.rb +0 -2
  250. data/lib/puppet/settings/config_file.rb +0 -2
  251. data/lib/puppet/settings/directory_setting.rb +0 -2
  252. data/lib/puppet/settings/duration_setting.rb +0 -2
  253. data/lib/puppet/settings/enum_setting.rb +16 -0
  254. data/lib/puppet/settings/file_setting.rb +0 -2
  255. data/lib/puppet/settings/path_setting.rb +0 -2
  256. data/lib/puppet/settings/string_setting.rb +0 -3
  257. data/lib/puppet/settings/terminus_setting.rb +0 -2
  258. data/lib/puppet/ssl/certificate_authority.rb +102 -9
  259. data/lib/puppet/test/test_helper.rb +1 -0
  260. data/lib/puppet/transaction.rb +130 -292
  261. data/lib/puppet/transaction/additional_resource_generator.rb +126 -0
  262. data/lib/puppet/transaction/event.rb +16 -1
  263. data/lib/puppet/transaction/report.rb +34 -14
  264. data/lib/puppet/transaction/resource_harness.rb +16 -19
  265. data/lib/puppet/type.rb +59 -53
  266. data/lib/puppet/type/component.rb +0 -2
  267. data/lib/puppet/type/cron.rb +13 -2
  268. data/lib/puppet/type/exec.rb +5 -7
  269. data/lib/puppet/type/file.rb +9 -32
  270. data/lib/puppet/type/file/content.rb +4 -1
  271. data/lib/puppet/type/file/ctime.rb +3 -1
  272. data/lib/puppet/type/file/ensure.rb +1 -1
  273. data/lib/puppet/type/file/mode.rb +0 -1
  274. data/lib/puppet/type/file/mtime.rb +2 -1
  275. data/lib/puppet/type/group.rb +7 -9
  276. data/lib/puppet/type/host.rb +1 -2
  277. data/lib/puppet/type/mcx.rb +0 -1
  278. data/lib/puppet/type/mount.rb +38 -6
  279. data/lib/puppet/type/package.rb +2 -2
  280. data/lib/puppet/type/resources.rb +5 -4
  281. data/lib/puppet/type/schedule.rb +1 -4
  282. data/lib/puppet/type/selmodule.rb +1 -1
  283. data/lib/puppet/type/service.rb +1 -3
  284. data/lib/puppet/type/tidy.rb +3 -3
  285. data/lib/puppet/type/user.rb +9 -13
  286. data/lib/puppet/type/yumrepo.rb +11 -7
  287. data/lib/puppet/util.rb +14 -7
  288. data/lib/puppet/util/autoload.rb +0 -1
  289. data/lib/puppet/util/backups.rb +1 -3
  290. data/lib/puppet/util/classgen.rb +1 -1
  291. data/lib/puppet/util/command_line/puppet_option_parser.rb +1 -3
  292. data/lib/puppet/util/command_line/trollop.rb +1 -1
  293. data/lib/puppet/util/constant_inflector.rb +1 -2
  294. data/lib/puppet/util/errors.rb +1 -0
  295. data/lib/puppet/util/file_watcher.rb +28 -0
  296. data/lib/puppet/util/fileparsing.rb +1 -3
  297. data/lib/puppet/util/filetype.rb +0 -1
  298. data/lib/puppet/util/http_proxy.rb +38 -0
  299. data/lib/puppet/util/ldap/manager.rb +1 -2
  300. data/lib/puppet/util/log.rb +31 -10
  301. data/lib/puppet/util/log/destinations.rb +0 -50
  302. data/lib/puppet/util/metric.rb +8 -1
  303. data/lib/puppet/util/monkey_patches.rb +14 -148
  304. data/lib/puppet/util/network_device/cisco/facts.rb +1 -1
  305. data/lib/puppet/util/network_device/config.rb +6 -9
  306. data/lib/puppet/util/network_device/transport/ssh.rb +1 -1
  307. data/lib/puppet/util/pidlock.rb +3 -0
  308. data/lib/puppet/util/posix.rb +1 -1
  309. data/lib/puppet/util/profiler.rb +1 -1
  310. data/lib/puppet/util/rdoc.rb +1 -1
  311. data/lib/puppet/util/rdoc/generators/puppet_generator.rb +0 -1
  312. data/lib/puppet/util/rdoc/generators/template/puppet/puppet.rb +50 -42
  313. data/lib/puppet/util/retryaction.rb +0 -1
  314. data/lib/puppet/util/symbolic_file_mode.rb +5 -1
  315. data/lib/puppet/util/tagging.rb +0 -2
  316. data/lib/puppet/util/warnings.rb +3 -0
  317. data/lib/puppet/util/watched_file.rb +37 -0
  318. data/lib/puppet/util/watcher.rb +17 -0
  319. data/lib/puppet/util/watcher/change_watcher.rb +33 -0
  320. data/lib/puppet/util/watcher/periodic_watcher.rb +37 -0
  321. data/lib/puppet/util/watcher/timer.rb +19 -0
  322. data/lib/puppet/util/windows/user.rb +1 -1
  323. data/lib/puppet/version.rb +1 -1
  324. data/lib/puppetx.rb +109 -0
  325. data/lib/puppetx/puppet/bindings_scheme_handler.rb +130 -0
  326. data/lib/puppetx/puppet/hiera2_backend.rb +31 -0
  327. data/lib/puppetx/puppet/syntax_checker.rb +91 -0
  328. data/lib/puppetx/puppetlabs/syntax_checkers/json.rb +39 -0
  329. data/lib/semver.rb +1 -1
  330. data/man/man8/puppet-kick.8 +1 -1
  331. data/spec/fixtures/integration/provider/cron/crontab/unspecialized +15 -0
  332. data/spec/fixtures/unit/pops/binder/bindings_composer/hiera1config/binder_config.yaml +18 -0
  333. data/spec/fixtures/unit/pops/binder/bindings_composer/hiera1config/hiera.yaml +8 -0
  334. data/spec/fixtures/unit/pops/binder/bindings_composer/hiera1config/modules/good/common.yaml +1 -0
  335. data/spec/fixtures/unit/pops/binder/bindings_composer/hiera1config/modules/good/hiera.yaml +10 -0
  336. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/binder_config.yaml +19 -0
  337. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/common.yaml +1 -0
  338. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/hiera.yaml +11 -0
  339. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/localhost.yaml +1 -0
  340. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/common.yaml +3 -0
  341. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/hiera.yaml +13 -0
  342. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/lib/puppet/bindings/awesome/default.rb +4 -0
  343. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/lib/puppetx/awesome/echo_backend.rb +11 -0
  344. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/lib/puppetx/awesome/echo_scheme_handler.rb +18 -0
  345. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/awesome/localhost.yaml +1 -0
  346. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/bad/common.yaml +3 -0
  347. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/bad/hiera_config.yaml +9 -0
  348. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/good/common.yaml +2 -0
  349. data/spec/fixtures/unit/pops/binder/bindings_composer/ok/modules/good/hiera.yaml +11 -0
  350. data/spec/fixtures/unit/pops/binder/config/binder_config/ok/binder_config.yaml +9 -0
  351. data/spec/fixtures/unit/pops/binder/hiera2/bindings_provider/ok/hiera.yaml +9 -0
  352. data/spec/fixtures/unit/pops/binder/hiera2/bindings_provider/ok/node.example.com.json +9 -0
  353. data/spec/fixtures/unit/pops/binder/hiera2/bindings_provider/ok/node.example.com.yaml +5 -0
  354. data/spec/fixtures/unit/pops/binder/hiera2/config/bad_syntax/hiera.yaml +10 -0
  355. data/spec/fixtures/unit/pops/binder/hiera2/config/malformed_hierarchy/hiera.yaml +8 -0
  356. data/spec/fixtures/unit/pops/binder/hiera2/config/missing/foo.txt +1 -0
  357. data/spec/fixtures/unit/pops/binder/hiera2/config/no_backends/hiera.yaml +7 -0
  358. data/spec/fixtures/unit/pops/binder/hiera2/config/no_hierarchy/hiera.yaml +4 -0
  359. data/spec/fixtures/unit/pops/binder/hiera2/config/not_a_hash/hiera.yaml +2 -0
  360. data/spec/fixtures/unit/pops/binder/hiera2/config/ok/hiera.yaml +8 -0
  361. data/spec/fixtures/unit/pops/binder/hiera2/yaml_backend/empty/common.yaml +0 -0
  362. data/spec/fixtures/unit/pops/binder/hiera2/yaml_backend/invalid/common.yaml +1 -0
  363. data/spec/fixtures/unit/pops/binder/hiera2/yaml_backend/ok/common.yaml +2 -0
  364. data/spec/fixtures/unit/provider/package/openbsd/pkginfo_flavors.list +2 -0
  365. data/spec/integration/agent/logging_spec.rb +178 -0
  366. data/spec/integration/configurer_spec.rb +1 -1
  367. data/spec/integration/defaults_spec.rb +0 -6
  368. data/spec/integration/network/authconfig_spec.rb +19 -0
  369. data/spec/integration/network/server/webrick_spec.rb +10 -11
  370. data/spec/integration/parser/catalog_spec.rb +85 -0
  371. data/spec/integration/provider/cron/crontab_spec.rb +11 -0
  372. data/spec/integration/provider/mount_spec.rb +1 -0
  373. data/spec/integration/transaction_spec.rb +8 -8
  374. data/spec/integration/type/file_spec.rb +1 -1
  375. data/spec/integration/util/settings_spec.rb +58 -11
  376. data/spec/lib/matchers/include_in_order.rb +21 -0
  377. data/spec/lib/matchers/include_in_order_spec.rb +30 -0
  378. data/spec/lib/matchers/relationship_graph_matchers.rb +48 -0
  379. data/spec/lib/puppet_spec/compiler.rb +24 -0
  380. data/spec/lib/puppet_spec/pops.rb +16 -0
  381. data/spec/spec_helper.rb +0 -1
  382. data/spec/unit/application/agent_spec.rb +145 -145
  383. data/spec/unit/application/apply_spec.rb +1 -1
  384. data/spec/unit/application/doc_spec.rb +1 -1
  385. data/spec/unit/application/face_base_spec.rb +3 -3
  386. data/spec/unit/application/facts_spec.rb +1 -0
  387. data/spec/unit/application/master_spec.rb +0 -15
  388. data/spec/unit/application/queue_spec.rb +6 -12
  389. data/spec/unit/application/resource_spec.rb +1 -1
  390. data/spec/unit/configurer/fact_handler_spec.rb +19 -50
  391. data/spec/unit/configurer_spec.rb +23 -7
  392. data/spec/unit/daemon_spec.rb +97 -121
  393. data/spec/unit/defaults_spec.rb +44 -0
  394. data/spec/unit/face/node_spec.rb +2 -2
  395. data/spec/unit/file_serving/configuration/parser_spec.rb +23 -33
  396. data/spec/unit/file_serving/configuration_spec.rb +2 -2
  397. data/spec/unit/file_serving/mount/file_spec.rb +4 -4
  398. data/spec/unit/forge/repository_spec.rb +9 -29
  399. data/spec/unit/graph/key_spec.rb +41 -0
  400. data/spec/unit/{rb_tree_map_spec.rb → graph/rb_tree_map_spec.rb} +7 -7
  401. data/spec/unit/graph/relationship_graph_spec.rb +393 -0
  402. data/spec/unit/graph/sequential_prioritizer_spec.rb +32 -0
  403. data/spec/unit/{simple_graph_spec.rb → graph/simple_graph.rb} +42 -254
  404. data/spec/unit/graph/title_hash_prioritizer_spec.rb +49 -0
  405. data/spec/unit/hiera_puppet_spec.rb +1 -1
  406. data/spec/unit/indirector/catalog/active_record_spec.rb +4 -2
  407. data/spec/unit/indirector/catalog/compiler_spec.rb +20 -26
  408. data/spec/unit/indirector/face_spec.rb +1 -1
  409. data/spec/unit/indirector/facts/facter_spec.rb +11 -1
  410. data/spec/unit/indirector/facts/network_device_spec.rb +11 -1
  411. data/spec/unit/indirector/hiera_spec.rb +1 -1
  412. data/spec/unit/indirector/instrumentation_data/local_spec.rb +1 -1
  413. data/spec/unit/indirector/instrumentation_listener/local_spec.rb +1 -1
  414. data/spec/unit/indirector/request_spec.rb +92 -39
  415. data/spec/unit/indirector/rest_spec.rb +1 -0
  416. data/spec/unit/indirector_spec.rb +2 -2
  417. data/spec/unit/interface/option_builder_spec.rb +1 -0
  418. data/spec/unit/interface/option_spec.rb +1 -0
  419. data/spec/unit/interface_spec.rb +2 -2
  420. data/spec/unit/module_tool/applications/installer_spec.rb +49 -2
  421. data/spec/unit/module_tool/metadata_spec.rb +13 -0
  422. data/spec/unit/network/authstore_spec.rb +1 -1
  423. data/spec/unit/network/format_handler_spec.rb +33 -282
  424. data/spec/unit/network/format_support_spec.rb +199 -0
  425. data/spec/unit/network/formats_spec.rb +2 -2
  426. data/spec/unit/network/http/connection_spec.rb +88 -7
  427. data/spec/unit/network/http/handler_spec.rb +271 -249
  428. data/spec/unit/network/http/rack/rest_spec.rb +1 -1
  429. data/spec/unit/network/http/webrick/rest_spec.rb +73 -22
  430. data/spec/unit/network/http_pool_spec.rb +40 -0
  431. data/spec/unit/network/server_spec.rb +18 -207
  432. data/spec/unit/node/facts_spec.rb +68 -17
  433. data/spec/unit/other/selinux_spec.rb +24 -20
  434. data/spec/unit/parameter/boolean_spec.rb +25 -0
  435. data/spec/unit/parameter/value_collection_spec.rb +7 -7
  436. data/spec/unit/parameter_spec.rb +10 -13
  437. data/spec/unit/parser/ast/function_spec.rb +4 -4
  438. data/spec/unit/parser/ast/leaf_spec.rb +45 -6
  439. data/spec/unit/parser/collector_spec.rb +3 -3
  440. data/spec/unit/parser/compiler_spec.rb +4 -3
  441. data/spec/unit/parser/functions/create_resources_spec.rb +9 -25
  442. data/spec/unit/parser/functions/extlookup_spec.rb +2 -2
  443. data/spec/unit/parser/functions/hiera_include_spec.rb +12 -0
  444. data/spec/unit/parser/functions/lookup_spec.rb +96 -0
  445. data/spec/unit/parser/functions/regsubst_spec.rb +2 -2
  446. data/spec/unit/parser/functions/split_spec.rb +2 -2
  447. data/spec/unit/parser/functions/sprintf_spec.rb +1 -1
  448. data/spec/unit/parser/functions/versioncmp_spec.rb +2 -2
  449. data/spec/unit/parser/functions_spec.rb +7 -7
  450. data/spec/unit/parser/lexer_spec.rb +1 -1
  451. data/spec/unit/parser/methods/collect_spec.rb +43 -0
  452. data/spec/unit/parser/resource_spec.rb +9 -9
  453. data/spec/unit/parser/scope_spec.rb +45 -2
  454. data/spec/unit/parser/type_loader_spec.rb +159 -175
  455. data/spec/unit/pops/binder/binder_spec.rb +62 -0
  456. data/spec/unit/pops/binder/bindings_checker_spec.rb +196 -0
  457. data/spec/unit/pops/binder/bindings_composer_spec.rb +89 -0
  458. data/spec/unit/pops/binder/bindings_validator_factory_spec.rb +18 -0
  459. data/spec/unit/pops/binder/config/binder_config_spec.rb +48 -0
  460. data/spec/unit/pops/binder/hiera2/bindings_provider_spec.rb +74 -0
  461. data/spec/unit/pops/binder/hiera2/config_spec.rb +61 -0
  462. data/spec/unit/pops/binder/hiera2/yaml_backend_spec.rb +33 -0
  463. data/spec/unit/pops/binder/injector_spec.rb +789 -0
  464. data/spec/unit/pops/containment_spec.rb +1 -0
  465. data/spec/unit/pops/issues_spec.rb +1 -1
  466. data/spec/unit/pops/parser/evaluating_parser_spec.rb +88 -0
  467. data/spec/unit/pops/parser/lexer_spec.rb +1 -1
  468. data/spec/unit/pops/parser/parse_calls_spec.rb +4 -0
  469. data/spec/unit/pops/parser/parser_spec.rb +1 -1
  470. data/spec/unit/pops/types/type_calculator_spec.rb +484 -0
  471. data/spec/unit/pops/types/type_factory_spec.rb +65 -0
  472. data/spec/unit/pops/types/type_parser_spec.rb +93 -0
  473. data/spec/unit/property/list_spec.rb +1 -1
  474. data/spec/unit/property/ordered_list_spec.rb +1 -1
  475. data/spec/unit/provider/aixobject_spec.rb +101 -0
  476. data/spec/unit/provider/augeas/augeas_spec.rb +14 -3
  477. data/spec/unit/provider/mcx/mcxcontent_spec.rb +52 -16
  478. data/spec/unit/provider/mount/parsed_spec.rb +44 -56
  479. data/spec/unit/provider/mount_spec.rb +11 -2
  480. data/spec/unit/provider/naginator_spec.rb +8 -0
  481. data/spec/unit/provider/package/apt_spec.rb +5 -1
  482. data/spec/unit/provider/package/aptitude_spec.rb +9 -5
  483. data/spec/unit/provider/package/aptrpm_spec.rb +2 -2
  484. data/spec/unit/provider/package/dpkg_spec.rb +274 -99
  485. data/spec/unit/provider/package/openbsd_spec.rb +84 -1
  486. data/spec/unit/provider/package/opkg_spec.rb +3 -3
  487. data/spec/unit/provider/package/pip_spec.rb +16 -0
  488. data/spec/unit/provider/package/pkgdmg_spec.rb +62 -7
  489. data/spec/unit/provider/package/rpm_spec.rb +112 -21
  490. data/spec/unit/provider/package/urpmi.rb +80 -0
  491. data/spec/unit/provider/package/windows/exe_package_spec.rb +1 -1
  492. data/spec/unit/provider/package/yum_spec.rb +85 -0
  493. data/spec/unit/provider/package/zypper_spec.rb +25 -6
  494. data/spec/unit/provider/parsedfile_spec.rb +3 -2
  495. data/spec/unit/provider/service/init_spec.rb +10 -10
  496. data/spec/unit/provider/service/openrc_spec.rb +16 -0
  497. data/spec/unit/provider/service/openwrt_spec.rb +1 -1
  498. data/spec/unit/provider/service/redhat_spec.rb +7 -0
  499. data/spec/unit/provider/ssh_authorized_key/parsed_spec.rb +2 -2
  500. data/spec/unit/provider/user/aix_spec.rb +89 -0
  501. data/spec/unit/provider/user/directoryservice_spec.rb +11 -4
  502. data/spec/unit/provider/user/user_role_add_spec.rb +18 -0
  503. data/spec/unit/provider_spec.rb +2 -13
  504. data/spec/unit/reports/http_spec.rb +1 -1
  505. data/spec/unit/resource/catalog_spec.rb +23 -97
  506. data/spec/unit/resource/resource_type.json +34 -0
  507. data/spec/unit/resource/status_spec.rb +56 -0
  508. data/spec/unit/resource/type_collection_spec.rb +6 -6
  509. data/spec/unit/resource/type_spec.rb +25 -5
  510. data/spec/unit/resource_spec.rb +68 -24
  511. data/spec/unit/run_spec.rb +16 -0
  512. data/spec/unit/scheduler/scheduler_spec.rb +14 -27
  513. data/spec/unit/semver_spec.rb +5 -0
  514. data/spec/unit/settings/enum_setting_spec.rb +27 -0
  515. data/spec/unit/settings_spec.rb +53 -44
  516. data/spec/unit/ssl/certificate_authority_spec.rb +155 -19
  517. data/spec/unit/transaction/additional_resource_generator_spec.rb +419 -0
  518. data/spec/unit/transaction/event_manager_spec.rb +2 -2
  519. data/spec/unit/transaction/event_spec.rb +57 -0
  520. data/spec/unit/transaction/report_spec.rb +66 -0
  521. data/spec/unit/transaction/resource_harness_spec.rb +27 -20
  522. data/spec/unit/transaction_spec.rb +182 -390
  523. data/spec/unit/type/augeas_spec.rb +3 -3
  524. data/spec/unit/type/component_spec.rb +0 -9
  525. data/spec/unit/type/computer_spec.rb +1 -1
  526. data/spec/unit/type/cron_spec.rb +2 -2
  527. data/spec/unit/type/exec_spec.rb +4 -2
  528. data/spec/unit/type/file/content_spec.rb +11 -0
  529. data/spec/unit/type/file/group_spec.rb +1 -1
  530. data/spec/unit/type/file_spec.rb +16 -8
  531. data/spec/unit/type/mount_spec.rb +445 -259
  532. data/spec/unit/type/package_spec.rb +4 -4
  533. data/spec/unit/type/resources_spec.rb +30 -1
  534. data/spec/unit/type/user_spec.rb +26 -3
  535. data/spec/unit/type/yumrepo_spec.rb +7 -27
  536. data/spec/unit/type/zone_spec.rb +4 -1
  537. data/spec/unit/type_spec.rb +66 -33
  538. data/spec/unit/util/backups_spec.rb +3 -3
  539. data/spec/unit/util/http_proxy_spec.rb +83 -0
  540. data/spec/unit/util/log_spec.rb +79 -8
  541. data/spec/unit/util/metric_spec.rb +12 -0
  542. data/spec/unit/util/monkey_patches_spec.rb +6 -0
  543. data/spec/unit/util/network_device/config_spec.rb +26 -64
  544. data/spec/unit/util/pidlock_spec.rb +4 -1
  545. data/spec/unit/util/tagging_spec.rb +5 -9
  546. data/spec/unit/util/warnings_spec.rb +1 -1
  547. data/spec/unit/util/watched_file_spec.rb +52 -0
  548. data/spec/unit/util/watcher/periodic_watcher_spec.rb +52 -0
  549. data/spec/unit/util/watcher_spec.rb +56 -0
  550. data/spec/unit/util_spec.rb +16 -0
  551. metadata +2767 -2576
  552. data/ext/debian/puppet.manpages +0 -32
  553. data/ext/osx/PackageInfo.plist +0 -36
  554. data/ext/osx/createpackage.sh +0 -187
  555. data/ext/redhat/rundir-perms.patch +0 -28
  556. data/lib/puppet/external/base64.rb +0 -19
  557. data/lib/puppet/util/graph.rb +0 -27
  558. data/lib/puppet/util/loadedfile.rb +0 -61
  559. data/lib/puppet/util/log_paths.rb +0 -22
  560. data/lib/puppet/util/subclass_loader.rb +0 -78
  561. data/spec/monkey_patches/publicize_methods.rb +0 -11
  562. data/spec/unit/util/loadedfile_spec.rb +0 -71
@@ -0,0 +1,10 @@
1
+ # The Hiera2 Module contains the classes needed to configure a bindings producer
2
+ # to read module specific data. The configuration is expected to be found in
3
+ # a hiera.yaml file in the root of each module
4
+ module Puppet::Pops::Binder::Hiera2
5
+ require 'puppet/pops/binder/hiera2/config_checker'
6
+ require 'puppet/pops/binder/hiera2/config'
7
+ require 'puppet/pops/binder/hiera2/diagnostic_producer'
8
+ require 'puppet/pops/binder/hiera2/bindings_provider'
9
+ require 'puppet/pops/binder/hiera2/issues'
10
+ end
@@ -0,0 +1,148 @@
1
+ module Puppet::Pops::Binder::Hiera2
2
+ Model = Puppet::Pops::Model
3
+
4
+ # A BindingsProvider instance is used for creating a bindings model from a module directory
5
+ # @api public
6
+ #
7
+ class BindingsProvider
8
+ # The resulting name of loaded bindings (given when initializing)
9
+ attr_reader :name
10
+
11
+ # Creates a new BindingsProvider by reading the hiera_conf.yaml configuration file. Problems
12
+ # with the configuration are reported propagated to the acceptor
13
+ #
14
+ # @param name [String] the name to assign to the result (and in error messages if there is no result)
15
+ # @param hiera_config_dir [String] Path to the directory containing a hiera_config
16
+ # @param acceptor [Puppet::Pops::Validation::Acceptor] Acceptor that will receive diagnostics
17
+ def initialize(name, hiera_config_dir, acceptor)
18
+ @name = name
19
+ @parser = Puppet::Pops::Parser::EvaluatingParser.new()
20
+ @diagnostics = DiagnosticProducer.new(acceptor)
21
+ @type_calculator = Puppet::Pops::Types::TypeCalculator.new()
22
+ @config = Config.new(hiera_config_dir, @diagnostics)
23
+ end
24
+
25
+ # Loads a bindings model using the hierarchy and backends configured for this instance.
26
+ #
27
+ # @param scope [Puppet::Parser::Scope] The hash used when expanding
28
+ # @return [Puppet::Pops::Binder::Bindings::ContributedBindings] A bindings model with effective categories
29
+ def load_bindings(scope)
30
+ backends = BackendHelper.new(scope)
31
+ factory = Puppet::Pops::Binder::BindingsFactory
32
+ result = factory.named_bindings(name)
33
+
34
+ hierarchy = {}
35
+ precedence = []
36
+
37
+ @config.hierarchy.each do |key, value, path|
38
+ source_file = File.join(@config.module_dir, 'hiera.config.yaml')
39
+ category_value = @parser.evaluate_string(scope, @parser.quote(value), source_file)
40
+
41
+ hierarchy[key] = {
42
+ :bindings => result.when_in_category(key, category_value),
43
+ :path => @parser.evaluate_string(scope, @parser.quote(path)),
44
+ :unique_keys =>Set.new()}
45
+
46
+ precedence << [key, category_value]
47
+ end
48
+
49
+ @config.backends.each do |backend_key|
50
+ backend = backends[backend_key]
51
+
52
+ hierarchy.each_pair do |hier_key, hier_val|
53
+ bindings = hier_val[:bindings]
54
+ unique_keys = hier_val[:unique_keys]
55
+
56
+ hiera_data_file_path = hier_val[:path]
57
+ backend.read_data(@config.module_dir, hiera_data_file_path).each_pair do |key, value|
58
+ if unique_keys.add?(key)
59
+ b = bindings.bind().name(key)
60
+ # Transform value into a Model::Expression
61
+ expr = build_expr(value, hiera_data_file_path)
62
+ if is_constant?(expr)
63
+ # The value is constant so toss the expression
64
+ b.type(@type_calculator.infer(value)).to(value)
65
+ else
66
+ # Use an evaluating producer for the binding
67
+ b.to(expr)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ factory.contributed_bindings(name, result.model, factory.categories(precedence))
75
+ end
76
+
77
+ private
78
+
79
+ # @return true unless the expression is a Model::ConcatenatedString or
80
+ # somehow contains one
81
+ def is_constant?(expr)
82
+ if expr.is_a?(Model::ConcatenatedString)
83
+ false
84
+ else
85
+ !expr.eAllContents.any? { |v| v.is_a?(Model::ConcatenatedString) }
86
+ end
87
+ end
88
+
89
+ # Transform the value into a Model::Expression. Strings are parsed using
90
+ # the Pops::Parser::Parser to produce either Model::LiteralString or Model::ConcatenatedString
91
+ #
92
+ # @param value [Object] May be an String, Number, TrueClass, FalseClass, or NilClass nested to any depth using Hash or Array.
93
+ # @param hiera_data_file_path [String] The source_file used when reporting errors
94
+ # @return [Model::Expression] The expression that corresponds to the value
95
+ def build_expr(value, hiera_data_file_path)
96
+ case value
97
+ when Symbol
98
+ value.to_s
99
+ when String
100
+ @parser.parse_string(@parser.quote(value)).current
101
+ when Hash
102
+ value.inject(Model::LiteralHash.new) do |h,(k,v)|
103
+ e = Model::KeyedEntry.new
104
+ e.key = build_expr(k, hiera_data_file_path)
105
+ e.value = build_expr(v, hiera_data_file_path)
106
+ h.addEntries(e)
107
+ h
108
+ end
109
+ when Enumerable
110
+ value.inject(Model::LiteralList.new) {|a,v| a.addValues(build_expr(v, hiera_data_file_path)); a }
111
+ when Numeric
112
+ expr = Model::LiteralNumber.new
113
+ expr.value = value;
114
+ expr
115
+ when TrueClass, FalseClass
116
+ expr = Model::LiteralBoolean.new
117
+ expr.value = value;
118
+ expr
119
+ when NilClass
120
+ Model::Nop.new
121
+ else
122
+ @diagnostics.accept(Issues::UNABLE_TO_PARSE_INSTANCE, value.class.name)
123
+ nil
124
+ end
125
+ end
126
+ end
127
+
128
+ # @api private
129
+ class BackendHelper
130
+ T = Puppet::Pops::Types::TypeFactory
131
+ HASH_OF_BACKENDS = T.hash_of(T.type_of('Puppetx::Puppet::Hiera2Backend'))
132
+ def initialize(scope)
133
+ @scope = scope
134
+ @cache = nil
135
+ end
136
+
137
+ def [] (backend_key)
138
+ load_backends unless @cache
139
+ @cache[backend_key]
140
+ end
141
+
142
+ def load_backends
143
+ @cache = @scope.compiler.boot_injector.lookup(@scope, HASH_OF_BACKENDS, Puppetx::HIERA2_BACKENDS) || {}
144
+ end
145
+ end
146
+
147
+ end
148
+
@@ -0,0 +1,69 @@
1
+ module Puppet::Pops::Binder::Hiera2
2
+
3
+ # Class holding the Hiera2 Configuration
4
+ # The configuration is obtained from the file 'hiera.yaml'
5
+ # that must reside in the root directory of the module
6
+ # @api public
7
+ #
8
+ class Puppet::Pops::Binder::Hiera2::Config
9
+ DEFAULT_HIERARCHY = [ ['osfamily', '${osfamily}', 'data/osfamily/${osfamily}'], ['common', 'true', 'data/common']]
10
+ DEFAULT_BACKENDS = ['yaml', 'json']
11
+
12
+ if defined?(::Psych::SyntaxError)
13
+ YamlLoadExceptions = [::StandardError, ::ArgumentError, ::Psych::SyntaxError]
14
+ else
15
+ YamlLoadExceptions = [::StandardError, ::ArgumentError]
16
+ end
17
+
18
+ # Returns a list of configured backends.
19
+ #
20
+ # @return [Array<String>] backend names
21
+ attr_reader :backends
22
+
23
+ # Root directory of the module holding the configuration
24
+ #
25
+ # @return [String] An absolute path
26
+ attr_reader :module_dir
27
+
28
+ # The bindings hierarchy is an array of categorizations where the
29
+ # array for each category has exactly three elements - the categorization name,
30
+ # category value, and the path that is later used by the backend to read
31
+ # the bindings for that category
32
+ #
33
+ # @return [Array<Array(String, String, String)>]
34
+ # @api public
35
+ attr_reader :hierarchy
36
+
37
+ # Creates a new Config. The configuration is loaded from the file 'hiera.yaml' which
38
+ # is expected to be found in the given module_dir.
39
+ #
40
+ # @param module_dir [String] The module directory
41
+ # @param diagnostics [DiagnosticProducer] collector of diagnostics
42
+ # @api public
43
+ #
44
+ def initialize(module_dir, diagnostics)
45
+ @module_dir = module_dir
46
+ config_file = File.join(module_dir, 'hiera.yaml')
47
+ validator = ConfigChecker.new(diagnostics)
48
+ begin
49
+ data = YAML.load_file(config_file)
50
+ validator.validate(data, config_file)
51
+ unless diagnostics.errors?
52
+ # if these are missing the result is nil, and they get default values later
53
+ @hierarchy = data['hierarchy']
54
+ @backends = data['backends']
55
+ end
56
+ rescue Errno::ENOENT
57
+ diagnostics.accept(Issues::CONFIG_FILE_NOT_FOUND, config_file)
58
+ rescue Errno::ENOTDIR
59
+ diagnostics.accept(Issues::CONFIG_FILE_NOT_FOUND, config_file)
60
+ rescue ::SyntaxError => e
61
+ diagnostics.accept(Issues::CONFIG_FILE_SYNTAX_ERROR, e)
62
+ rescue *YamlLoadExceptions => e
63
+ diagnostics.accept(Issues::CONFIG_FILE_SYNTAX_ERROR, e)
64
+ end
65
+ @hierarchy ||= DEFAULT_HIERARCHY
66
+ @backends ||= DEFAULT_BACKENDS
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,68 @@
1
+ module Puppet::Pops::Binder::Hiera2
2
+
3
+ # Validates the consistency of a Hiera2::Config
4
+ class ConfigChecker
5
+
6
+ # Create an instance with a diagnostic producer that will receive the result during validation
7
+ # @param diangostics [DiagnosticProducer] The producer that will receive the diagnostic
8
+ def initialize(diagnostics)
9
+ @diagnostics = diagnostics
10
+ end
11
+
12
+ # Validate the consistency of the given data. Diagnostics will be emitted to the DiagnosticProducer
13
+ # that was set when this checker was created
14
+ #
15
+ # @param data [Object] The data read from the config file
16
+ # @param config_file [String] The full path of the file. Used in error messages
17
+ def validate(data, config_file)
18
+ if data.is_a?(Hash)
19
+ # If the version is missing, it is not meaningful to continue
20
+ return unless check_version(data['version'], config_file)
21
+ check_hierarchy(data['hierarchy'], config_file)
22
+ check_backends(data['backends'], config_file)
23
+ else
24
+ @diagnostics.accept(Issues::CONFIG_IS_NOT_HASH, config_file)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ # Version is required and must be >= 2. A warning is issued if version > 2 as this checker is
31
+ # for version 2 only.
32
+ # @return [Boolean] false if it is meaningless to continue checking
33
+ def check_version(version, config_file)
34
+ if version.nil?
35
+ # This is not hiera2 compatible
36
+ @diagnostics.accept(Issues::MISSING_VERSION, config_file)
37
+ return false
38
+ end
39
+ unless version >= 2
40
+ @diagnostics.accept(Issues::WRONG_VERSION, config_file, :expected => 2, :actual => version)
41
+ return false
42
+ end
43
+ unless version == 2
44
+ # it may have a sane subset, hence a different error (configured as warning)
45
+ @diagnostics.accept(Issues::LATER_VERSION, config_file, :expected => 2, :actual => version)
46
+ end
47
+ return true
48
+ end
49
+
50
+ def check_hierarchy(hierarchy, config_file)
51
+ if !hierarchy.is_a?(Array) || hierarchy.empty?
52
+ @diagnostics.accept(Issues::MISSING_HIERARCHY, config_file)
53
+ else
54
+ hierarchy.each do |value|
55
+ unless value.is_a?(Array) && value.length() == 3
56
+ @diagnostics.accept(Issues::CATEGORY_MUST_BE_THREE_ELEMENT_ARRAY, config_file)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def check_backends(backends, config_file)
63
+ if !backends.is_a?(Array) || backends.empty?
64
+ @diagnostics.accept(Issues::MISSING_BACKENDS, config_file)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,36 @@
1
+ module Puppet::Pops::Binder::Hiera2
2
+ # Generates validation diagnostics
3
+ class Puppet::Pops::Binder::Hiera2::DiagnosticProducer
4
+ attr_reader :acceptor
5
+ def initialize(an_acceptor)
6
+ raise ArgumentError, "Not an acceptor" unless an_acceptor.is_a?(Puppet::Pops::Validation::Acceptor)
7
+ @acceptor = an_acceptor
8
+ @severity_producer = Puppet::Pops::Validation::SeverityProducer.new
9
+ end
10
+
11
+ def accept(issue, semantic, arguments={})
12
+ arguments[:semantic] ||= semantic
13
+ severity = severity_producer.severity(issue)
14
+ acceptor.accept(Puppet::Pops::Validation::Diagnostic.new(severity, issue, nil, nil, arguments))
15
+ end
16
+
17
+ def errors?()
18
+ acceptor.errors?
19
+ end
20
+
21
+ def severity_producer
22
+ p = @severity_producer
23
+ p[Issues::UNRESOLVED_STRING_VARIABLE] = :warning
24
+
25
+ # Warning since if it does not blow up on anything else, a sane subset of later version was used
26
+ p[Issues::LATER_VERSION] = :warning
27
+
28
+ # Ignore MISSING_BACKENDS because a default will be provided
29
+ p[Issues::MISSING_BACKENDS] = :ignore
30
+
31
+ # Ignore MISSING_HIERARCHY because a default will be provided
32
+ p[Issues::MISSING_HIERARCHY] = :ignore
33
+ p
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,67 @@
1
+ module Puppet::Pops::Binder::Hiera2::Issues
2
+ # (see Puppet::Pops::Issues#issue)
3
+ def self.issue (issue_code, *args, &block)
4
+ Puppet::Pops::Issues.issue(issue_code, *args, &block)
5
+ end
6
+
7
+ CONFIG_IS_NOT_HASH = issue :CONFIG_IS_NOT_HASH do
8
+ "The configuration file '#{semantic}' has no hash at the top level"
9
+ end
10
+
11
+ MISSING_HIERARCHY = issue :MISSING_HIERARCHY do
12
+ "The configuration file '#{semantic}' contains no hierarchy"
13
+ end
14
+
15
+ MISSING_BACKENDS = issue :MISSING_BACKENDS do
16
+ "The configuration file '#{semantic}' contains no backends"
17
+ end
18
+
19
+ CATEGORY_MUST_BE_THREE_ELEMENT_ARRAY = issue :CATEGORY_MUST_BE_THREE_ELEMENT_ARRAY do
20
+ "The configuration file '#{semantic}' has a malformed hierarchy (should consist of arrays with three string entries)"
21
+ end
22
+
23
+ CONFIG_FILE_NOT_FOUND = issue :CONFIG_FILE_NOT_FOUND do
24
+ "The configuration file '#{semantic}' does not exist"
25
+ end
26
+
27
+ CONFIG_FILE_SYNTAX_ERROR = issue :CONFIG_FILE_SYNTAX_ERROR do
28
+ "Unable to parse: #{semantic}"
29
+ end
30
+
31
+ CANNOT_LOAD_BACKEND = issue :CANNOT_LOAD_BACKEND, :key, :error do
32
+ "Backend '#{key}' in configuration file '#{semantic}' cannot be loaded: #{error}"
33
+ end
34
+
35
+ BACKEND_FILE_DOES_NOT_DEFINE_CLASS = issue :BACKEND_FILE_DOES_NOT_DEFINE_CLASS, :class_name do
36
+ "The file '#{semantic}' does not define class #{class_name}"
37
+ end
38
+
39
+ NOT_A_BACKEND_CLASS = issue :NOT_A_BACKEND_CLASS, :key, :class_name do
40
+ "Class #{class_name}, loaded using key #{key} in file '#{semantic}' is not a subclass of Backend"
41
+ end
42
+
43
+ METADATA_JSON_NOT_FOUND = issue :METADATA_JSON_NOT_FOUND do
44
+ "The metadata file '#{semantic}' does not exist"
45
+ end
46
+
47
+ UNSUPPORTED_STRING_EXPRESSION = issue :UNSUPPORTED_STRING_EXPRESSION, :expr do
48
+ "String '#{semantic}' contains an unsupported expression (type was #{expr.class.name})"
49
+ end
50
+
51
+ UNRESOLVED_STRING_VARIABLE = issue :UNRESOLVED_STRING_VARIABLE, :key do
52
+ "Variable '#{key}' found in string '#{semantic}' cannot be resolved"
53
+ end
54
+
55
+ MISSING_VERSION = issue :MISSING_VERSION do
56
+ "The configuration file '#{semantic}' does not have a version."
57
+ end
58
+
59
+ WRONG_VERSION = issue :WRONG_VERSION do
60
+ "The configuration file '#{semantic}' has the wrong version, expected: #{expected}, actual: #{actual}"
61
+ end
62
+
63
+ LATER_VERSION = issue :LATER_VERSION do
64
+ "The configuration file '#{semantic}' has a version that is newer (features may not work), expected: #{expected}, actual: #{actual}"
65
+ end
66
+
67
+ end
@@ -0,0 +1,18 @@
1
+ require 'json'
2
+
3
+ # A Backend implementation capable of reading JSON syntax
4
+ class Puppet::Pops::Binder::Hiera2::JsonBackend < Puppetx::Puppet::Hiera2Backend
5
+ def read_data(module_dir, source)
6
+ begin
7
+ source_file = File.join(module_dir, "#{source}.json")
8
+ JSON.parse(File.read(source_file))
9
+ rescue Errno::ENOTDIR
10
+ # This is OK, the file doesn't need to be present. Return an empty hash
11
+ {}
12
+ rescue Errno::ENOENT
13
+ # This is OK, the file doesn't need to be present. Return an empty hash
14
+ {}
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,21 @@
1
+ # A Backend implementation capable of reading YAML syntax
2
+ class Puppet::Pops::Binder::Hiera2::YamlBackend < Puppetx::Puppet::Hiera2Backend
3
+ def read_data(module_dir, source)
4
+ begin
5
+ source_file = File.join(module_dir, "#{source}.yaml")
6
+ # if file is present but empty or has only "---", YAML.load_file returns false,
7
+ # in which case fall back to returning an empty hash
8
+ YAML.load_file(source_file) || {}
9
+ rescue TypeError => e
10
+ # SafeYaml chokes when trying to load using utf-8 and the file is empty
11
+ raise e if File.size?(source_file)
12
+ {}
13
+ rescue Errno::ENOTDIR
14
+ # This is OK, the file doesn't need to be present. Return an empty hash
15
+ {}
16
+ rescue Errno::ENOENT
17
+ # This is OK, the file doesn't need to be present. Return an empty hash
18
+ {}
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,688 @@
1
+ # The injector is the "lookup service" class
2
+ #
3
+ # Initialization
4
+ # --------------
5
+ # The injector is initialized with a configured {Puppet::Pops::Binder::Binder Binder}. The Binder instance contains a resolved set of
6
+ # `key => "binding information"` that is used to setup the injector.
7
+ #
8
+ # Lookup
9
+ # ------
10
+ # It is possible to lookup either the value, or a producer of the value. The {#lookup} method looks up a value, and the
11
+ # {#lookup_producer} looks up a producer.
12
+ # Both of these methods can be called with three different signatures; `lookup(key)`, `lookup(type, name)`, and `lookup(name)`,
13
+ # with the corresponding calls to obtain a producer; `lookup_producer(key)`, `lookup_producer(type, name)`, and `lookup_producer(name)`.
14
+ #
15
+ # It is possible to pass a block to {#lookup} and {#lookup_producer}, the block is passed the result of the lookup
16
+ # and the result of the block is returned as the value of the lookup. This is useful in order to provide a default value.
17
+ #
18
+ # @example Lookup with default value
19
+ # injector.lookup('favourite_food') {|x| x.nil? ? 'bacon' : x }
20
+ #
21
+ # Singleton or Not
22
+ # ----------------
23
+ # The lookup of a value is always based on the lookup of a producer. For *singleton producers* this means that the value is
24
+ # determined by the first value lookup. Subsequent lookups via `lookup` or `lookup_producer` will produce the same instance.
25
+ #
26
+ # *Non singleton producers* will produce a new instance on each request for a value. For constant value producers this
27
+ # means that a new deep-clone is produced for mutable objects (but not for immutable objects as this is not needed).
28
+ # Custom producers should have non singleton behavior, or if this is not possible ensure that the produced result is
29
+ # immutable. (The behavior if a custom producer hands out a mutable value and this is mutated is undefined).
30
+ #
31
+ # Custom bound producers capable of producing a series of objects when bound as a singleton means that the producer
32
+ # is a singleton, not the value it produces. If such a producer is bound as non singleton, each `lookup` will get a new
33
+ # producer (hence, typically, restarting the series). However, the producer returned from `lookup_producer` will not
34
+ # recreate the producer on each call to `produce`; i.e. each `lookup_producer` returns a producer capable of returning
35
+ # a series of objects.
36
+ #
37
+ # @see Puppet::Pops::Binder::Binder Binder, for details about how to bind keys to producers
38
+ # @see Puppet::Pops::Binder::BindingsFactory BindingsFactory, for a convenient way to create a Binder and bindings
39
+ #
40
+ # Assisted Inject
41
+ # ---------------
42
+ # The injector supports lookup of instances of classes *even if the requested class is not explicitly bound*.
43
+ # This is possible for classes that have a zero argument `initialize` method, or that has a class method called
44
+ # `inject` that takes two arguments; `injector`, and `scope`.
45
+ # This is useful in ruby logic as a class can then use the given injector to inject details.
46
+ # An `inject` class method wins over a zero argument `initialize` in all cases.
47
+ #
48
+ # @example Using assisted inject
49
+ # # Class with assisted inject support
50
+ # class Duck
51
+ # attr_reader :name, :year_of_birth
52
+ #
53
+ # def self.inject(injector, scope, binding, *args)
54
+ # # lookup default name and year of birth, and use defaults if not present
55
+ # name = injector.lookup(scope,'default-duck-name') {|x| x ? x : 'Donald Duck' }
56
+ # year_of_birth = injector.lookup(scope,'default-duck-year_of_birth') {|x| x ? x : 1934 }
57
+ # self.new(name, year_of_birth)
58
+ # end
59
+ #
60
+ # def initialize(name, year_of_birth)
61
+ # @name = name
62
+ # @year_of_birth = year_of_birth
63
+ # end
64
+ # end
65
+ #
66
+ # injector.lookup(scope, Duck)
67
+ # # Produces a Duck named 'Donald Duck' or named after the binding 'default-duck-name' (and with similar treatment of
68
+ # # year_of_birth).
69
+ # @see Puppet::Pops::Binder::Producers::AssistedInjectProducer AssistedInjectProducer, for more details on assisted injection
70
+ #
71
+ # Access to key factory and type calculator
72
+ # -----------------------------------------
73
+ # It is important to use the same key factory, and type calculator as the binder. It is therefor possible to obtaint
74
+ # these with the methods {#key_factory}, and {#type_calculator}.
75
+ #
76
+ # Special support for producers
77
+ # -----------------------------
78
+ # There is one method specially designed for producers. The {#get_contributions} method returns an array of all contributions
79
+ # to a given *contributions key*. This key is obtained from the {#key_factory} for a given multibinding. The returned set of
80
+ # contributed bindings is sorted in descending precedence order. Any conflicts, merges, etc. is performed by the multibinding
81
+ # producer configured for a multibinding.
82
+ #
83
+ # @api public
84
+ #
85
+ class Puppet::Pops::Binder::Injector
86
+
87
+ Producers = Puppet::Pops::Binder::Producers
88
+
89
+ # An Injector is initialized with a configured {Puppet::Pops::Binder::Binder Binder}.
90
+ #
91
+ # @param configured_binder [Puppet::Pops::Binder::Binder,nil] The configured binder containing effective bindings. A given value
92
+ # of nil creates an injector that returns or yields nil on all lookup requests.
93
+ # @raise ArgumentError if the given binder is not fully configured
94
+ #
95
+ # @api public
96
+ #
97
+ def initialize(configured_binder)
98
+ if configured_binder.nil?
99
+ @impl = Private::NullInjectorImpl.new()
100
+ else
101
+ @impl = Private::InjectorImpl.new(configured_binder)
102
+ end
103
+ end
104
+
105
+ # The KeyFactory used to produce keys in this injector.
106
+ # The factory is shared with the Binder to ensure consistent translation to keys.
107
+ # A compatible type calculator can also be obtained from the key factory.
108
+ # @return [Puppet::Pops::Binder::KeyFactory] the key factory in use
109
+ #
110
+ # @api public
111
+ #
112
+ def key_factory()
113
+ @impl.key_factory
114
+ end
115
+
116
+ # Returns the TypeCalculator in use for keys. The same calculator (as used for keys) should be used if there is a need
117
+ # to check type conformance, or infer the type of Ruby objects.
118
+ #
119
+ # @return [Puppet::Pops::Types::TypeCalculator] the type calculator that is in use for keys
120
+ # @api public
121
+ #
122
+ def type_calculator()
123
+ @impl.type_calculator()
124
+ end
125
+
126
+ # Lookup (a.k.a "inject") of a value given a key.
127
+ # The lookup may be called with different parameters. This method is a convenience method that
128
+ # dispatches to one of #lookup_key or #lookup_type depending on the arguments. It also provides
129
+ # the ability to use an optional block that is called with the looked up value, or scope and value if the
130
+ # block takes two parameters. This is useful to provide a default value or other transformations, calculations
131
+ # based on the result of the lookup.
132
+ #
133
+ # @overload lookup(scope, key)
134
+ # (see #lookup_key)
135
+ # @param scope [Puppet::Parser::Scope] the scope to use for evaluation
136
+ # @param key [Object] an opaque object being the full key
137
+ #
138
+ # @overload lookup(scope, type, name = '')
139
+ # (see #lookup_type)
140
+ # @param scope [Puppet::Parser::Scope] the scope to use for evaluation
141
+ # @param type [Puppet::Pops::Types::PObjectType] the type of what to lookup
142
+ # @param name [String] the name to use, defaults to empty string (for unnamed)
143
+ #
144
+ # @overload lookup(scope, name)
145
+ # Lookup of Data type with given name.
146
+ # @see #lookup_type
147
+ # @param scope [Puppet::Parser::Scope] the scope to use for evaluation
148
+ # @param name [String] the Data/name to lookup
149
+ #
150
+ # @yield [value] passes the looked up value to an optional block and returns what this block returns
151
+ # @yield [scope, value] passes scope and value to the block and returns what this block returns
152
+ # @yieldparam scope [Puppet::Parser::Scope] the scope given to lookup
153
+ # @yieldparam value [Object, nil] the looked up value or nil if nothing was found
154
+ #
155
+ # @raise [ArgumentError] if the block has an arity that is not 1 or 2
156
+ #
157
+ # @api public
158
+ #
159
+ def lookup(scope, *args, &block)
160
+ @impl.lookup(scope, *args, &block)
161
+ end
162
+
163
+ # Looks up a (typesafe) value based on a type/name combination.
164
+ # Creates a key for the type/name combination using a KeyFactory. Specialization of the Data type are transformed
165
+ # to a Data key, and the result is type checked to conform with the given key.
166
+ #
167
+ # @param type [Puppet::Pops::Types::PObjectType] the type to lookup as defined by Puppet::Pops::Types::TypeFactory
168
+ # @param name [String] the (optional for non `Data` types) name of the entry to lookup.
169
+ # The name may be an empty String (the default), but not nil. The name is required for lookup for subtypes of
170
+ # `Data`.
171
+ # @return [Object, nil] the looked up bound object, or nil if not found (type conformance with given type is guaranteed)
172
+ # @raise [ArgumentError] if the produced value does not conform with the given type
173
+ #
174
+ # @api public
175
+ #
176
+ def lookup_type(scope, type, name='')
177
+ @impl.lookup_type(scope, type, name)
178
+ end
179
+
180
+ # Looks up the key and returns the entry, or nil if no entry is found.
181
+ # Produced type is checked for type conformance with its binding, but not with the lookup key.
182
+ # (This since all subtypes of PDataType are looked up using a key based on PDataType).
183
+ # Use the Puppet::Pops::Types::TypeCalculator#instance? method to check for conformance of the result
184
+ # if this is wanted, or use #lookup_type.
185
+ #
186
+ # @param key [Object] lookup of key as produced by the key factory
187
+ # @return [Object, nil] produced value of type that conforms with bound type (type conformance with key not guaranteed).
188
+ # @raise [ArgumentError] if the produced value does not conform with the bound type
189
+ #
190
+ # @api public
191
+ #
192
+ def lookup_key(scope, key)
193
+ @impl.lookup_key(scope, key)
194
+ end
195
+
196
+ # Lookup (a.k.a "inject") producer of a value given a key.
197
+ # The producer lookup may be called with different parameters. This method is a convenience method that
198
+ # dispatches to one of #lookup_producer_key or #lookup_producer_type depending on the arguments. It also provides
199
+ # the ability to use an optional block that is called with the looked up producer, or scope and producer if the
200
+ # block takes two parameters. This is useful to provide a default value, call a custom producer method,
201
+ # or other transformations, calculations based on the result of the lookup.
202
+ #
203
+ # @overload lookup_producer(scope, key)
204
+ # (see #lookup_proudcer_key)
205
+ # @param scope [Puppet::Parser::Scope] the scope to use for evaluation
206
+ # @param key [Object] an opaque object being the full key
207
+ #
208
+ # @overload lookup_producer(scope, type, name = '')
209
+ # (see #lookup_type)
210
+ # @param scope [Puppet::Parser::Scope] the scope to use for evaluation
211
+ # @param type [Puppet::Pops::Types::PObjectType], the type of what to lookup
212
+ # @param name [String], the name to use, defaults to empty string (for unnamed)
213
+ #
214
+ # @overload lookup_producer(scope, name)
215
+ # Lookup of Data type with given name.
216
+ # @see #lookup_type
217
+ # @param scope [Puppet::Parser::Scope] the scope to use for evaluation
218
+ # @param name [String], the Data/name to lookup
219
+ #
220
+ # @return [Puppet::Pops::Binder::Producers::Producer, Object, nil] a producer, or what the optional block returns
221
+ #
222
+ # @yield [producer] passes the looked up producer to an optional block and returns what this block returns
223
+ # @yield [scope, producer] passes scope and producer to the block and returns what this block returns
224
+ # @yieldparam producer [Puppet::Pops::Binder::Producers::Producer, nil] the looked up producer or nil if nothing was bound
225
+ # @yieldparam scope [Puppet::Parser::Scope] the scope given to lookup
226
+ #
227
+ # @raise [ArgumentError] if the block has an arity that is not 1 or 2
228
+ #
229
+ # @api public
230
+ #
231
+ def lookup_producer(scope, *args, &block)
232
+ @impl.lookup_producer(scope, *args, &block)
233
+ end
234
+
235
+ # Looks up a Producer given an opaque binder key.
236
+ # @return [Puppet::Pops::Binder::Producers::Producer, nil] the bound producer, or nil if no such producer was found.
237
+ #
238
+ # @api public
239
+ #
240
+ def lookup_producer_key(scope, key)
241
+ @impl.lookup_producer_key(scope, key)
242
+ end
243
+
244
+ # Looks up a Producer given a type/name key.
245
+ # @note The result is not type checked (it cannot be until the producer has produced an instance).
246
+ # @return [Puppet::Pops::Binder::Producers::Producer, nil] the bound producer, or nil if no such producer was found
247
+ #
248
+ # @api public
249
+ #
250
+ def lookup_producer_type(scope, type, name='')
251
+ @impl.lookup_producer_type(scope, type, name)
252
+ end
253
+
254
+ # Returns the contributions to a multibind given its contribution key (as produced by the KeyFactory).
255
+ # This method is typically used by multibind value producers, but may be used for introspection of the injector's state.
256
+ #
257
+ # @param scope [Puppet::Parser::Scope] the scope to use
258
+ # @param contributions_key [Object] Opaque key as produced by KeyFactory as the contributions key for a multibinding
259
+ # @return [Array<Puppet::Pops::Binder::InjectorEntry>] the contributions sorted in deecending order of precedence
260
+ #
261
+ # @api public
262
+ #
263
+ def get_contributions(scope, contributions_key)
264
+ @impl.get_contributions(scope, contributions_key)
265
+ end
266
+
267
+ # Returns an Injector that returns (or yields) nil on all lookups, and produces an empty structure for contributions
268
+ # This method is intended for testing purposes.
269
+ #
270
+ def self.null_injector
271
+ self.new(nil)
272
+ end
273
+
274
+ # The implementation of the Injector is private.
275
+ # @see Puppet::Pops::Binder::Injector The public API this module implements.
276
+ # @api private
277
+ #
278
+ module Private
279
+
280
+ # This is a mocking "Null" implementation of Injector. It never finds anything
281
+ # @api private
282
+ class NullInjectorImpl
283
+ attr_reader :entries
284
+ attr_reader :key_factory
285
+ attr_reader :type_calculator
286
+
287
+ def initialize
288
+ @entries = []
289
+ @key_factory = Puppet::Pops::Binder::KeyFactory.new()
290
+ @type_calculator = @key_factory.type_calculator
291
+ end
292
+
293
+ def lookup(scope, *args, &block)
294
+ raise ArgumentError, "lookup should be called with two or three arguments, got: #{args.size()+1}" unless args.size.between?(1,2)
295
+ # call block with result if given
296
+ if block
297
+ case block.arity
298
+ when 1
299
+ block.call(:undef)
300
+ when 2
301
+ block.call(scope, :undef)
302
+ else
303
+ raise ArgumentError, "The block should have arity 1 or 2"
304
+ end
305
+ else
306
+ val
307
+ end
308
+
309
+ end
310
+
311
+ # @api private
312
+ def lookup_key(scope, key)
313
+ nil
314
+ end
315
+
316
+ # @api private
317
+ def lookup_producer(scope, *args, &block)
318
+ lookup(scope, *args, &block)
319
+ end
320
+
321
+ # @api private
322
+ def lookup_producer_key(scope, key)
323
+ nil
324
+ end
325
+
326
+ # @api private
327
+ def lookup_producer_type(scope, type, name='')
328
+ nil
329
+ end
330
+
331
+ def get_contributions()
332
+ []
333
+ end
334
+ end
335
+
336
+ # @api private
337
+ #
338
+ class InjectorImpl
339
+ # Hash of key => InjectorEntry
340
+ # @api private
341
+ #
342
+ attr_reader :entries
343
+
344
+ attr_reader :key_factory
345
+
346
+ attr_reader :type_calculator
347
+
348
+ def initialize(configured_binder)
349
+ raise ArgumentError, "Given Binder is not configured" unless configured_binder && configured_binder.configured?()
350
+ @entries = configured_binder.injector_entries()
351
+
352
+ # It is essential that the injector uses the same key factory as the binder since keys must be
353
+ # represented the same (but still opaque) way.
354
+ #
355
+ @key_factory = configured_binder.key_factory()
356
+ @type_calculator = key_factory.type_calculator()
357
+ @@transform_visitor ||= Puppet::Pops::Visitor.new(nil,"transform", 2, 2)
358
+ @recursion_lock = [ ]
359
+ end
360
+
361
+ # @api private
362
+ def lookup(scope, *args, &block)
363
+ raise ArgumentError, "lookup should be called with two or three arguments, got: #{args.size()+1}" unless args.size.between?(1,2)
364
+
365
+ val = case args[ 0 ]
366
+
367
+ when Puppet::Pops::Types::PObjectType
368
+ lookup_type(scope, *args)
369
+
370
+ when String
371
+ raise ArgumentError, "lookup of name should only pass the name" unless args.size == 1
372
+ lookup_key(scope, key_factory.data_key(args[ 0 ]))
373
+
374
+ else
375
+ raise ArgumentError, 'lookup using a key should only pass a single key' unless args.size == 1
376
+ lookup_key(scope, args[ 0 ])
377
+ end
378
+
379
+ # call block with result if given
380
+ if block
381
+ case block.arity
382
+ when 1
383
+ block.call(val)
384
+ when 2
385
+ block.call(scope, val)
386
+ else
387
+ raise ArgumentError, "The block should have arity 1 or 2"
388
+ end
389
+ else
390
+ val
391
+ end
392
+ end
393
+
394
+ # Produces a key for a type/name combination.
395
+ # @api private
396
+ def named_key(type, name)
397
+ key_factory.named_key(type, name)
398
+ end
399
+
400
+ # Produces a key for a PDataType/name combination
401
+ # @api private
402
+ def data_key(name)
403
+ key_factory.data_key(name)
404
+ end
405
+
406
+ # @api private
407
+ def lookup_type(scope, type, name='')
408
+ val = lookup_key(scope, named_key(type, name))
409
+ unless key_factory.type_calculator.instance?(type, val)
410
+ raise ArgumentError, "Type error: incompatible type, #{type_error_detail(type, val)}"
411
+ end
412
+ val
413
+ end
414
+
415
+ # @api private
416
+ def type_error_detail(expected, actual)
417
+ actual_t = type_calculator.infer(actual)
418
+ "expected: #{type_calculator.string(expected)}, got: #{type_calculator.string(actual_t)}"
419
+ end
420
+
421
+ # @api private
422
+ def lookup_key(scope, key)
423
+ if @recursion_lock.include?(key)
424
+ raise ArgumentError, "Lookup loop detected for key: #{key}"
425
+ end
426
+ begin
427
+ @recursion_lock.push(key)
428
+ case entry = get_entry(key)
429
+ when NilClass
430
+ nil
431
+ when Puppet::Pops::Binder::InjectorEntry
432
+ val = produce(scope, entry)
433
+ return nil if val.nil?
434
+ unless key_factory.type_calculator.instance?(entry.binding.type, val)
435
+ raise "Type error: incompatible type returned by producer, #{type_error_detail(entry.binding.type, val)}"
436
+ end
437
+ val
438
+ when Producers::AssistedInjectProducer
439
+ entry.produce(scope)
440
+ else
441
+ # internal, direct entries
442
+ entry
443
+ end
444
+ ensure
445
+ @recursion_lock.pop()
446
+ end
447
+ end
448
+
449
+ # Should be used to get entries as it converts missing entries to NotFound entries or AssistedInject entries
450
+ #
451
+ # @api private
452
+ def get_entry(key)
453
+ case entry = entries[ key ]
454
+ when NilClass
455
+ # not found, is this an assisted inject?
456
+ if clazz = assistable_injected_class(key)
457
+ entry = Producers::AssistedInjectProducer.new(self, clazz)
458
+ entries[ key ] = entry
459
+ else
460
+ entries[ key ] = NotFound.new()
461
+ entry = nil
462
+ end
463
+ when NotFound
464
+ entry = nil
465
+ end
466
+ entry
467
+ end
468
+
469
+ # Returns contributions to a multibind in precedence order; highest first.
470
+ # Returns an Array on the form [ [key, entry], [key, entry]] where the key is intended to be used to lookup the value
471
+ # (or a producer) for that entry.
472
+ # @api private
473
+ def get_contributions(scope, contributions_key)
474
+ result = {}
475
+ return [] unless contributions = lookup_key(scope, contributions_key)
476
+ contributions.each { |k| result[k] = get_entry(k) }
477
+ result.sort {|a, b| a[0] <=> b[0] }
478
+ #result.sort_by {|key, entry| entry }
479
+ end
480
+
481
+ # Produces an injectable class given a key, or nil if key does not represent an injectable class
482
+ # @api private
483
+ #
484
+ def assistable_injected_class(key)
485
+ kt = key_factory.get_type(key)
486
+ return nil unless kt.is_a?(Puppet::Pops::Types::PRubyType) && !key_factory.is_named?(key)
487
+ type_calculator.injectable_class(kt)
488
+ end
489
+
490
+ def lookup_producer(scope, *args, &block)
491
+ raise ArgumentError, "lookup_producer should be called with two or three arguments, got: #{args.size()+1}" unless args.size <= 2
492
+
493
+ p = case args[ 0 ]
494
+ when Puppet::Pops::Types::PObjectType
495
+ lookup_producer_type(scope, *args)
496
+
497
+ when String
498
+ raise ArgumentError, "lookup_producer of name should only pass the name" unless args.size == 1
499
+ lookup_producer_key(scope, key_factory.data_key(args[ 0 ]))
500
+
501
+ else
502
+ raise ArgumentError, "lookup_producer using a key should only pass a single key" unless args.size == 1
503
+ lookup_producer_key(scope, args[ 0 ])
504
+ end
505
+
506
+ # call block with result if given
507
+ if block
508
+ case block.arity
509
+ when 1
510
+ block.call(p)
511
+ when 2
512
+ block.call(scope, p)
513
+ else
514
+ raise ArgumentError, "The block should have arity 1 or 2"
515
+ end
516
+ else
517
+ p
518
+ end
519
+ end
520
+
521
+ # @api private
522
+ def lookup_producer_key(scope, key)
523
+ if @recursion_lock.include?(key)
524
+ raise ArgumentError, "Lookup loop detected for key: #{key}"
525
+ end
526
+ begin
527
+ @recursion_lock.push(key)
528
+ producer(scope, get_entry(key), :multiple_use)
529
+ ensure
530
+ @recursion_lock.pop()
531
+ end
532
+ end
533
+
534
+ # @api private
535
+ def lookup_producer_type(scope, type, name='')
536
+ lookup_producer_key(scope, named_key(type, name))
537
+ end
538
+
539
+ # Returns the producer for the entry
540
+ # @return [Puppet::Pops::Binder::Producers::Producer] the entry's producer.
541
+ #
542
+ # @api private
543
+ #
544
+ def producer(scope, entry, use)
545
+ return nil unless entry # not found
546
+ return entry.producer(scope) if entry.is_a?(Producers::AssistedInjectProducer)
547
+ unless entry.cached_producer
548
+ entry.cached_producer = transform(entry.binding.producer, scope, entry)
549
+ end
550
+ unless entry.cached_producer
551
+ raise ArgumentError, "Injector entry without a producer #{format_binding(entry.binding)}"
552
+ end
553
+ entry.cached_producer.producer(scope)
554
+ end
555
+
556
+ # @api private
557
+ def transform(producer_descriptor, scope, entry)
558
+ @@transform_visitor.visit_this(self, producer_descriptor, scope, entry)
559
+ end
560
+
561
+ # Returns the produced instance
562
+ # @return [Object] the produced instance
563
+ # @api private
564
+ #
565
+ def produce(scope, entry)
566
+ return nil unless entry # not found
567
+ producer(scope, entry, :single_use).produce(scope)
568
+ end
569
+
570
+ # @api private
571
+ def named_arguments_to_hash(named_args)
572
+ nb = named_args.nil? ? [] : named_args
573
+ result = {}
574
+ nb.each {|arg| result[ :"#{arg.name}" ] = arg.value }
575
+ result
576
+ end
577
+
578
+ # @api private
579
+ def merge_producer_options(binding, options)
580
+ named_arguments_to_hash(binding.producer_args).merge(options)
581
+ end
582
+
583
+ # @api private
584
+ def format_binding(b)
585
+ Puppet::Pops::Binder::Binder.format_binding(b)
586
+ end
587
+
588
+ # Handles a missing producer (which is valid for a Multibinding where one is selected automatically)
589
+ # @api private
590
+ #
591
+ def transform_NilClass(descriptor, scope, entry)
592
+ unless entry.binding.is_a?(Puppet::Pops::Binder::Bindings::Multibinding)
593
+ raise ArgumentError, "Binding without producer detected, #{format_binding(entry.binding)}"
594
+ end
595
+ case entry.binding.type
596
+ when Puppet::Pops::Types::PArrayType
597
+ transform(Puppet::Pops::Binder::Bindings::ArrayMultibindProducerDescriptor.new(), scope, entry)
598
+ when Puppet::Pops::Types::PHashType
599
+ transform(Puppet::Pops::Binder::Bindings::HashMultibindProducerDescriptor.new(), scope, entry)
600
+ else
601
+ raise ArgumentError, "Unsupported multibind type, must be an array or hash type, #{format_binding(entry.binding)}"
602
+ end
603
+ end
604
+
605
+ # @api private
606
+ def transform_ArrayMultibindProducerDescriptor(descriptor, scope, entry)
607
+ make_producer(Producers::ArrayMultibindProducer, descriptor, scope, entry, named_arguments_to_hash(entry.binding.producer_args))
608
+ end
609
+
610
+ # @api private
611
+ def transform_HashMultibindProducerDescriptor(descriptor, scope, entry)
612
+ make_producer(Producers::HashMultibindProducer, descriptor, scope, entry, named_arguments_to_hash(entry.binding.producer_args))
613
+ end
614
+
615
+ # @api private
616
+ def transform_ConstantProducerDescriptor(descriptor, scope, entry)
617
+ producer_class = singleton?(descriptor) ? Producers::SingletonProducer : Producers::DeepCloningProducer
618
+ producer_class.new(self, entry.binding, scope, merge_producer_options(entry.binding, {:value => descriptor.value}))
619
+ end
620
+
621
+ # @api private
622
+ def transform_InstanceProducerDescriptor(descriptor, scope, entry)
623
+ make_producer(Producers::InstantiatingProducer, descriptor, scope, entry,
624
+ merge_producer_options(entry.binding, {:class_name => descriptor.class_name, :init_args => descriptor.arguments}))
625
+ end
626
+
627
+ # @api private
628
+ def transform_EvaluatingProducerDescriptor(descriptor, scope, entry)
629
+ make_producer(Producers::EvaluatingProducer, descriptor, scope, entry,
630
+ merge_producer_options(entry.binding, {:expression => descriptor.expression}))
631
+ end
632
+
633
+ # @api private
634
+ def make_producer(clazz, descriptor, scope, entry, options)
635
+ singleton_wrapped(descriptor, scope, entry, clazz.new(self, entry.binding, scope, options))
636
+ end
637
+
638
+ # @api private
639
+ def singleton_wrapped(descriptor, scope, entry, producer)
640
+ return producer unless singleton?(descriptor)
641
+ Producers::SingletonProducer.new(self, entry.binding, scope,
642
+ merge_producer_options(entry.binding, {:value => producer.produce(scope)}))
643
+ end
644
+
645
+ # @api private
646
+ def transform_ProducerProducerDescriptor(descriptor, scope, entry)
647
+ p = transform(descriptor.producer, scope, entry)
648
+ clazz = singleton?(descriptor) ? Producers::SingletonProducerProducer : Producers::ProducerProducer
649
+ clazz.new(self, entry.binding, scope, merge_producer_options(entry.binding,
650
+ merge_producer_options(entry.binding, { :producer_producer => p })))
651
+ end
652
+
653
+ # @api private
654
+ def transform_LookupProducerDescriptor(descriptor, scope, entry)
655
+ make_producer(Producers::LookupProducer, descriptor, scope, entry,
656
+ merge_producer_options(entry.binding, {:type => descriptor.type, :name => descriptor.name}))
657
+ end
658
+
659
+ # @api private
660
+ def transform_HashLookupProducerDescriptor(descriptor, scope, entry)
661
+ make_producer(Producers::LookupKeyProducer, descriptor, scope, entry,
662
+ merge_producer_options(entry.binding, {:type => descriptor.type, :name => descriptor.name, :key => descriptor.key}))
663
+ end
664
+
665
+ # @api private
666
+ def transform_NonCachingProducerDescriptor(descriptor, scope, entry)
667
+ # simply delegates to the wrapped producer
668
+ transform(descriptor.producer, scope, entry)
669
+ end
670
+
671
+ # @api private
672
+ def transform_FirstFoundProducerDescriptor(descriptor, scope, entry)
673
+ make_producer(Producers::FirstFoundProducer, descriptor, scope, entry,
674
+ merge_producer_options(entry.binding, {:producers => descriptor.producers.collect {|p| transform(p, scope, entry) }}))
675
+ end
676
+
677
+ # @api private
678
+ def singleton?(descriptor)
679
+ ! descriptor.eContainer().is_a?(Puppet::Pops::Binder::Bindings::NonCachingProducerDescriptor)
680
+ end
681
+
682
+ # Special marker class used in entries
683
+ # @api private
684
+ class NotFound
685
+ end
686
+ end
687
+ end
688
+ end