puppet 6.0.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/Gemfile.lock +20 -20
  4. data/Guardfile.example +76 -0
  5. data/LICENSE +189 -4
  6. data/README.md +3 -3
  7. data/Rakefile +5 -2
  8. data/ext/solaris/smf/svc-puppetd +8 -1
  9. data/ext/solaris/smf/svc-puppetmasterd +8 -1
  10. data/lib/puppet/application/apply.rb +100 -59
  11. data/lib/puppet/application/cert.rb +4 -114
  12. data/lib/puppet/application/device.rb +48 -32
  13. data/lib/puppet/application/script.rb +1 -1
  14. data/lib/puppet/application/ssl.rb +135 -51
  15. data/lib/puppet/application.rb +5 -0
  16. data/lib/puppet/configurer.rb +2 -3
  17. data/lib/puppet/defaults.rb +33 -49
  18. data/lib/puppet/etc.rb +20 -0
  19. data/lib/puppet/face/config.rb +3 -3
  20. data/lib/puppet/face/key.rb +1 -1
  21. data/lib/puppet/face/node/clean.rb +0 -1
  22. data/lib/puppet/feature/base.rb +1 -1
  23. data/lib/puppet/file_bucket/dipper.rb +1 -1
  24. data/lib/puppet/file_serving/fileset.rb +1 -1
  25. data/lib/puppet/functions/abs.rb +1 -1
  26. data/lib/puppet/functions/new.rb +1 -1
  27. data/lib/puppet/module/task.rb +29 -38
  28. data/lib/puppet/pal/catalog_compiler.rb +96 -0
  29. data/lib/puppet/pal/compiler.rb +221 -0
  30. data/lib/puppet/pal/function_signature.rb +52 -0
  31. data/lib/puppet/pal/json_catalog_encoder.rb +67 -0
  32. data/lib/puppet/pal/pal_api.rb +15 -0
  33. data/lib/puppet/pal/pal_impl.rb +523 -0
  34. data/lib/puppet/pal/plan_signature.rb +71 -0
  35. data/lib/puppet/pal/script_compiler.rb +71 -0
  36. data/lib/puppet/pal/task_signature.rb +58 -0
  37. data/lib/puppet/parser/catalog_compiler.rb +24 -0
  38. data/lib/puppet/parser/compiler.rb +3 -1
  39. data/lib/puppet/parser/functions/generate.rb +7 -6
  40. data/lib/puppet/plugins/configuration.rb +5 -1
  41. data/lib/puppet/pops/evaluator/collectors/abstract_collector.rb +3 -1
  42. data/lib/puppet/pops/evaluator/deferred_resolver.rb +3 -0
  43. data/lib/puppet/pops/evaluator/evaluator_impl.rb +5 -1
  44. data/lib/puppet/pops/evaluator/external_syntax_support.rb +3 -3
  45. data/lib/puppet/pops/evaluator/runtime3_converter.rb +2 -2
  46. data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +19 -10
  47. data/lib/puppet/pops/loader/task_instantiator.rb +13 -70
  48. data/lib/puppet/pops/parser/heredoc_support.rb +1 -2
  49. data/lib/puppet/pops/parser/lexer2.rb +1 -1
  50. data/lib/puppet/pops/pcore.rb +10 -33
  51. data/lib/puppet/pops/serialization/to_data_converter.rb +9 -1
  52. data/lib/puppet/pops/serialization.rb +1 -0
  53. data/lib/puppet/pops/types/p_timespan_type.rb +2 -2
  54. data/lib/puppet/pops/types/string_converter.rb +18 -4
  55. data/lib/puppet/pops/validation/checker4_0.rb +17 -2
  56. data/lib/puppet/provider/exec.rb +59 -57
  57. data/lib/puppet/provider/group/aix.rb +18 -2
  58. data/lib/puppet/provider/group/windows_adsi.rb +7 -3
  59. data/lib/puppet/provider/nameservice.rb +1 -25
  60. data/lib/puppet/provider/package/dnf.rb +2 -0
  61. data/lib/puppet/provider/package/pkgng.rb +37 -21
  62. data/lib/puppet/provider/package/portage.rb +2 -2
  63. data/lib/puppet/provider/package/windows/exe_package.rb +16 -10
  64. data/lib/puppet/provider/package/windows/msi_package.rb +8 -0
  65. data/lib/puppet/provider/package/windows/package.rb +9 -1
  66. data/lib/puppet/provider/package/windows.rb +2 -2
  67. data/lib/puppet/provider/package/yum.rb +1 -1
  68. data/lib/puppet/provider/parsedfile.rb +25 -4
  69. data/lib/puppet/provider/service/launchd.rb +19 -3
  70. data/lib/puppet/provider/service/smf.rb +54 -0
  71. data/lib/puppet/provider/service/systemd.rb +19 -0
  72. data/lib/puppet/provider/service/upstart.rb +1 -0
  73. data/lib/puppet/provider/service/windows.rb +22 -5
  74. data/lib/puppet/provider/user/aix.rb +48 -2
  75. data/lib/puppet/provider/user/useradd.rb +2 -10
  76. data/lib/puppet/provider/user/windows_adsi.rb +9 -1
  77. data/lib/puppet/resource/catalog.rb +1 -5
  78. data/lib/puppet/resource.rb +3 -1
  79. data/lib/puppet/ssl/host.rb +26 -16
  80. data/lib/puppet/syntax_checkers/epp.rb +34 -0
  81. data/lib/puppet/syntax_checkers/pp.rb +34 -0
  82. data/lib/puppet/transaction/event_manager.rb +13 -1
  83. data/lib/puppet/transaction/persistence.rb +1 -1
  84. data/lib/puppet/transaction/resource_harness.rb +3 -1
  85. data/lib/puppet/type/group.rb +29 -1
  86. data/lib/puppet/type/package.rb +5 -1
  87. data/lib/puppet/type/resources.rb +12 -2
  88. data/lib/puppet/type/schedule.rb +7 -0
  89. data/lib/puppet/type/service.rb +12 -0
  90. data/lib/puppet/type/user.rb +5 -2
  91. data/lib/puppet/type.rb +6 -0
  92. data/lib/puppet/util/command_line.rb +2 -3
  93. data/lib/puppet/util/execution.rb +15 -1
  94. data/lib/puppet/util/filetype.rb +56 -8
  95. data/lib/puppet/util/log/destinations.rb +3 -2
  96. data/lib/puppet/util/logging.rb +3 -2
  97. data/lib/puppet/util/posix.rb +15 -0
  98. data/lib/puppet/util/selinux.rb +1 -1
  99. data/lib/puppet/util/storage.rb +12 -0
  100. data/lib/puppet/util/windows/adsi.rb +79 -2
  101. data/lib/puppet/util/windows/api_types.rb +1 -1
  102. data/lib/puppet/util/windows/process.rb +23 -3
  103. data/lib/puppet/util/windows/registry.rb +29 -5
  104. data/lib/puppet/util/windows/security.rb +14 -0
  105. data/lib/puppet/util/windows/service.rb +294 -74
  106. data/lib/puppet/util/windows/user.rb +3 -5
  107. data/lib/puppet/util.rb +7 -3
  108. data/lib/puppet/version.rb +1 -1
  109. data/lib/puppet.rb +1 -0
  110. data/lib/puppet_pal.rb +5 -1099
  111. data/locales/ja/puppet.po +952 -986
  112. data/locales/puppet.pot +592 -347
  113. data/man/man5/puppet.conf.5 +26 -31
  114. data/man/man8/puppet-agent.8 +1 -1
  115. data/man/man8/puppet-apply.8 +1 -1
  116. data/man/man8/puppet-catalog.8 +1 -1
  117. data/man/man8/puppet-config.8 +4 -4
  118. data/man/man8/puppet-describe.8 +1 -1
  119. data/man/man8/puppet-device.8 +23 -19
  120. data/man/man8/puppet-doc.8 +1 -1
  121. data/man/man8/puppet-epp.8 +1 -1
  122. data/man/man8/puppet-facts.8 +1 -1
  123. data/man/man8/puppet-filebucket.8 +1 -1
  124. data/man/man8/puppet-generate.8 +1 -1
  125. data/man/man8/puppet-help.8 +1 -1
  126. data/man/man8/puppet-key.8 +2 -2
  127. data/man/man8/puppet-lookup.8 +1 -1
  128. data/man/man8/puppet-man.8 +1 -1
  129. data/man/man8/puppet-module.8 +1 -1
  130. data/man/man8/puppet-node.8 +1 -1
  131. data/man/man8/puppet-parser.8 +1 -1
  132. data/man/man8/puppet-plugin.8 +1 -1
  133. data/man/man8/puppet-report.8 +1 -1
  134. data/man/man8/puppet-resource.8 +1 -1
  135. data/man/man8/puppet-script.8 +1 -1
  136. data/man/man8/puppet-ssl.8 +26 -3
  137. data/man/man8/puppet-status.8 +1 -1
  138. data/man/man8/puppet.8 +2 -2
  139. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load.rb +11 -0
  140. data/spec/fixtures/unit/provider/package/pkgng/pkg.query +7 -1
  141. data/spec/fixtures/unit/provider/package/pkgng/pkg.query.zsh +1 -0
  142. data/spec/fixtures/unit/provider/service/smf/svcs_fmri.out +6 -0
  143. data/spec/fixtures/unit/provider/service/smf/svcs_multiple_fmris.out +13 -0
  144. data/spec/integration/application/apply_spec.rb +4 -1
  145. data/spec/integration/parser/collection_spec.rb +4 -8
  146. data/spec/integration/provider/service/windows_spec.rb +5 -5
  147. data/spec/integration/ssl/key_spec.rb +0 -4
  148. data/spec/integration/transaction_spec.rb +559 -0
  149. data/spec/integration/type/file_spec.rb +6 -6
  150. data/spec/integration/util/windows/registry_spec.rb +39 -0
  151. data/spec/integration/util/windows/security_spec.rb +10 -7
  152. data/spec/integration/util/windows/user_spec.rb +37 -17
  153. data/spec/lib/puppet/test_ca.rb +1 -1
  154. data/spec/spec_helper.rb +1 -1
  155. data/spec/unit/agent_spec.rb +2 -2
  156. data/spec/unit/application/apply_spec.rb +55 -2
  157. data/spec/unit/application/device_spec.rb +10 -7
  158. data/spec/unit/application/face_base_spec.rb +1 -1
  159. data/spec/unit/application/lookup_spec.rb +2 -1
  160. data/spec/unit/application/ssl_spec.rb +178 -109
  161. data/spec/unit/application_spec.rb +29 -11
  162. data/spec/unit/configurer/downloader_spec.rb +1 -1
  163. data/spec/unit/configurer_spec.rb +16 -5
  164. data/spec/unit/etc_spec.rb +25 -0
  165. data/spec/unit/face/node_spec.rb +1 -3
  166. data/spec/unit/face/parser_spec.rb +15 -0
  167. data/spec/unit/file_serving/fileset_spec.rb +11 -11
  168. data/spec/unit/functions/logging_spec.rb +10 -3
  169. data/spec/unit/indirector/catalog/json_spec.rb +9 -3
  170. data/spec/unit/indirector/yaml_spec.rb +1 -1
  171. data/spec/unit/network/http/connection_spec.rb +2 -2
  172. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +36 -0
  173. data/spec/unit/pops/evaluator/runtime3_converter_spec.rb +22 -4
  174. data/spec/unit/pops/loaders/loader_spec.rb +9 -17
  175. data/spec/unit/pops/loaders/loaders_spec.rb +48 -0
  176. data/spec/unit/pops/loaders/module_loaders_spec.rb +7 -7
  177. data/spec/unit/pops/parser/parse_heredoc_spec.rb +16 -0
  178. data/spec/unit/pops/serialization/to_from_hr_spec.rb +9 -0
  179. data/spec/unit/pops/types/p_timespan_type_spec.rb +22 -0
  180. data/spec/unit/pops/types/p_timestamp_type_spec.rb +19 -0
  181. data/spec/unit/pops/types/string_converter_spec.rb +25 -1
  182. data/spec/unit/pops/types/task_spec.rb +42 -116
  183. data/spec/unit/pops/validator/validator_spec.rb +24 -10
  184. data/spec/unit/provider/exec/posix_spec.rb +24 -0
  185. data/spec/unit/provider/group/aix_spec.rb +20 -6
  186. data/spec/unit/provider/group/ldap_spec.rb +22 -25
  187. data/spec/unit/provider/group/pw_spec.rb +7 -10
  188. data/spec/unit/provider/group/windows_adsi_spec.rb +42 -33
  189. data/spec/unit/provider/nameservice/directoryservice_spec.rb +97 -103
  190. data/spec/unit/provider/package/aix_spec.rb +5 -8
  191. data/spec/unit/provider/package/apt_spec.rb +3 -6
  192. data/spec/unit/provider/package/dnf_spec.rb +38 -25
  193. data/spec/unit/provider/package/dpkg_spec.rb +18 -21
  194. data/spec/unit/provider/package/freebsd_spec.rb +4 -7
  195. data/spec/unit/provider/package/gem_spec.rb +41 -41
  196. data/spec/unit/provider/package/hpux_spec.rb +7 -10
  197. data/spec/unit/provider/package/macports_spec.rb +13 -15
  198. data/spec/unit/provider/package/nim_spec.rb +3 -10
  199. data/spec/unit/provider/package/openbsd_spec.rb +14 -17
  200. data/spec/unit/provider/package/pip3_spec.rb +3 -6
  201. data/spec/unit/provider/package/pip_spec.rb +45 -49
  202. data/spec/unit/provider/package/pkgin_spec.rb +13 -18
  203. data/spec/unit/provider/package/pkgng_spec.rb +32 -27
  204. data/spec/unit/provider/package/puppet_gem_spec.rb +6 -9
  205. data/spec/unit/provider/package/tdnf_spec.rb +9 -12
  206. data/spec/unit/provider/package/windows/exe_package_spec.rb +3 -3
  207. data/spec/unit/provider/package/windows_spec.rb +4 -4
  208. data/spec/unit/provider/package/yum_spec.rb +30 -16
  209. data/spec/unit/provider/package/zypper_spec.rb +17 -19
  210. data/spec/unit/provider/service/bsd_spec.rb +7 -9
  211. data/spec/unit/provider/service/daemontools_spec.rb +12 -16
  212. data/spec/unit/provider/service/debian_spec.rb +6 -10
  213. data/spec/unit/provider/service/freebsd_spec.rb +2 -2
  214. data/spec/unit/provider/service/launchd_spec.rb +19 -0
  215. data/spec/unit/provider/service/openbsd_spec.rb +13 -17
  216. data/spec/unit/provider/service/rcng_spec.rb +2 -4
  217. data/spec/unit/provider/service/redhat_spec.rb +12 -11
  218. data/spec/unit/provider/service/runit_spec.rb +7 -14
  219. data/spec/unit/provider/service/smf_spec.rb +77 -13
  220. data/spec/unit/provider/service/src_spec.rb +11 -16
  221. data/spec/unit/provider/service/systemd_spec.rb +39 -1
  222. data/spec/unit/provider/service/windows_spec.rb +39 -7
  223. data/spec/unit/provider/user/aix_spec.rb +43 -2
  224. data/spec/unit/provider/user/hpux_spec.rb +3 -5
  225. data/spec/unit/provider/user/ldap_spec.rb +29 -32
  226. data/spec/unit/provider/user/pw_spec.rb +10 -13
  227. data/spec/unit/provider/user/useradd_spec.rb +2 -2
  228. data/spec/unit/provider/user/windows_adsi_spec.rb +4 -4
  229. data/spec/unit/puppet_pal_2pec.rb +6 -6
  230. data/spec/unit/puppet_pal_catalog_spec.rb +58 -0
  231. data/spec/unit/resource/catalog_spec.rb +2 -2
  232. data/spec/unit/resource_spec.rb +31 -0
  233. data/spec/unit/ssl/host_spec.rb +22 -1
  234. data/spec/unit/ssl/key_spec.rb +2 -4
  235. data/spec/unit/task_spec.rb +50 -5
  236. data/spec/unit/transaction/event_manager_spec.rb +12 -1
  237. data/spec/unit/transaction/persistence_spec.rb +4 -4
  238. data/spec/unit/transaction/resource_harness_spec.rb +18 -0
  239. data/spec/unit/type/group_spec.rb +11 -3
  240. data/spec/unit/type/resources_spec.rb +18 -0
  241. data/spec/unit/type/service_spec.rb +27 -1
  242. data/spec/unit/util/execution_spec.rb +77 -0
  243. data/spec/unit/util/filetype_spec.rb +13 -5
  244. data/spec/unit/util/log/destinations_spec.rb +10 -0
  245. data/spec/unit/util/logging_spec.rb +58 -41
  246. data/spec/unit/util/monkey_patches_spec.rb +18 -5
  247. data/spec/unit/util/posix_spec.rb +28 -0
  248. data/spec/unit/util/selinux_spec.rb +4 -0
  249. data/spec/unit/util/storage_spec.rb +107 -0
  250. data/spec/unit/util/suidmanager_spec.rb +1 -3
  251. data/spec/unit/util/windows/adsi_spec.rb +95 -0
  252. data/spec/unit/util/windows/service_spec.rb +377 -131
  253. metadata +24 -11
  254. data/ext/autotest/Rakefile +0 -8
  255. data/ext/autotest/config +0 -43
  256. data/ext/autotest/readme.rst +0 -16
  257. data/spec/fixtures/unit/provider/package/pkgng/pkg.info +0 -7
  258. data/spec/fixtures/unit/provider/package/pkgng/pkg.query_absent +0 -1
  259. data/spec/watchr.rb +0 -137
@@ -71,19 +71,22 @@ class Puppet::Module
71
71
 
72
72
  { "name" => name, "path" => path }
73
73
  end
74
+ private_class_method :get_file_details
74
75
 
75
- # Find task's required lib files and retrieve paths
76
- # for both 'files' and 'implementation:files' metadata keys
77
- def self.find_files(files, mod)
78
- env = mod.environment.respond_to?(:name) ? mod.environment.name : 'production'
76
+ # Find task's required lib files and retrieve paths for both 'files' and 'implementation:files' metadata keys
77
+ def self.find_extra_files(metadata, envname = nil)
78
+ return [] if metadata.nil?
79
79
 
80
- file_list = files.flat_map do |file|
80
+ files = metadata.fetch('files', []) +
81
+ metadata.fetch('implementations', []).flat_map { |impl| impl.fetch('files', []) }
82
+
83
+ files.uniq.flat_map do |file|
81
84
  module_name, mount, endpath = file.split("/", 3)
82
85
  # If there's a mount directory with no trailing slash this will be nil
83
86
  # We want it to be empty to construct a path
84
87
  endpath ||= ''
85
88
 
86
- pup_module = Puppet::Module.find(module_name, env)
89
+ pup_module = Puppet::Module.find(module_name, envname)
87
90
  if pup_module.nil?
88
91
  msg = _("Could not find module %{module_name} containing task file %{filename}" %
89
92
  {module_name: module_name, filename: endpath})
@@ -114,22 +117,18 @@ class Puppet::Module
114
117
  raise InvalidMetadata.new(msg, 'puppet.tasks/invalid-metadata')
115
118
  end
116
119
  dir_files = Dir.glob("#{path}**/*").select { |f| File.file?(f) }
117
- files = dir_files.map { |f| get_file_details(f, pup_module) }
120
+ dir_files.map { |f| get_file_details(f, pup_module) }
118
121
  else
119
122
  if last_char
120
123
  msg = _("Files specified in task metadata cannot include a trailing slash: %{file}" % { file: file } )
121
124
  raise InvalidMetadata.new(msg, 'puppet.task/invalid-metadata')
122
125
  end
123
- files = get_file_details(path, pup_module)
126
+ get_file_details(path, pup_module)
124
127
  end
125
-
126
- files
127
128
  end
128
- return file_list
129
129
  end
130
+ private_class_method :find_extra_files
130
131
 
131
- # Copied from TaskInstantiator so we can use the Error classes here
132
- # TODO: harmonize on one implementation
133
132
  # Executables list should contain the full path of all possible implementation files
134
133
  def self.find_implementations(name, directory, metadata, executables)
135
134
  basename = name.split('::')[1] || 'init'
@@ -148,7 +147,7 @@ class Puppet::Module
148
147
  msg = _("Task metadata for task %{name} specifies missing implementation %{implementation}" % { name: name, implementation: impl['name'] })
149
148
  raise InvalidTask.new(msg, 'puppet.tasks/missing-implementation', { missing: [impl['name']] } )
150
149
  end
151
- { "name" => impl['name'], "requirements" => impl.fetch('requirements', []), "path" => path }
150
+ { "name" => impl['name'], "path" => path }
152
151
  end
153
152
  return implementations
154
153
  end
@@ -166,7 +165,13 @@ class Puppet::Module
166
165
  raise InvalidTask.new(msg, 'puppet.tasks/multiple-implementations')
167
166
  end
168
167
 
169
- [{ "name" => File.basename(implementations.first), "path" => implementations.first, "requirements" => [] }]
168
+ [{ "name" => File.basename(implementations.first), "path" => implementations.first }]
169
+ end
170
+ private_class_method :find_implementations
171
+
172
+ def self.find_files(name, directory, metadata, executables, envname = nil)
173
+ # PXP agent relies on 'impls' (which is the task file) being first if there is no metadata
174
+ find_implementations(name, directory, metadata, executables) + find_extra_files(metadata, envname)
170
175
  end
171
176
 
172
177
  def self.is_tasks_metadata_filename?(name)
@@ -206,7 +211,7 @@ class Puppet::Module
206
211
  @module_executables = module_executables || []
207
212
  end
208
213
 
209
- def read_metadata(file)
214
+ def self.read_metadata(file)
210
215
  Puppet::Util::Json.load(Puppet::FileSystem.read(file, :encoding => 'utf-8')) if file
211
216
  rescue SystemCallError, IOError => err
212
217
  msg = _("Error reading metadata: %{message}" % {message: err.message})
@@ -216,34 +221,15 @@ class Puppet::Module
216
221
  end
217
222
 
218
223
  def metadata
219
- @metadata ||= read_metadata(@metadata_file)
220
- end
221
-
222
- def implementations
223
- @implementations ||= self.class.find_implementations(@name, @module.tasks_directory, metadata, @module_executables)
224
+ @metadata ||= self.class.read_metadata(@metadata_file)
224
225
  end
225
226
 
226
227
  def files
227
- md = metadata
228
- outer_files = []
229
- impl_lib_files = []
230
- lib_files = []
231
-
232
- unless md.nil?
233
- outer_files = md['files'] if md.key?('files')
234
- # There's definitely a more elegant way to do this...
235
- if md.key?('implementations')
236
- md['implementations'].each { |impl| impl_lib_files << impl['files'] if impl.key?('files') }
237
- end
238
- lib_files = self.class.find_files((impl_lib_files.flatten.uniq + outer_files).uniq, @module)
239
- end
240
- task_file = implementations.map {|imp| { 'name' => imp['name'], 'path' => imp['path'] } }
241
- # PXP agent relies on 'impls' (which is the task file) being first if there is no metadata
242
- task_file + lib_files
228
+ @files ||= self.class.find_files(@name, @module.tasks_directory, metadata, @module_executables, environment_name)
243
229
  end
244
230
 
245
231
  def validate
246
- implementations
232
+ files
247
233
  true
248
234
  end
249
235
 
@@ -252,6 +238,11 @@ class Puppet::Module
252
238
  self.module == other.module
253
239
  end
254
240
 
241
+ def environment_name
242
+ @module.environment.respond_to?(:name) ? @module.environment.name : 'production'
243
+ end
244
+ private :environment_name
245
+
255
246
  def self.new_with_files(pup_module, name, task_files, module_executables)
256
247
  metadata_file = task_files.find { |f| is_tasks_metadata_filename?(f) }
257
248
  Puppet::Module::Task.new(pup_module, name, module_executables, metadata_file)
@@ -0,0 +1,96 @@
1
+ module Puppet
2
+ module Pal
3
+ # A CatalogCompiler is a compiler that builds a catalog of resources and dependencies as a side effect of
4
+ # evaluating puppet language code.
5
+ # When the compilation of the given input manifest(s)/code string/file is finished the catalog is complete
6
+ # for encoding and use. It is also possible to evaluate more strings within the same compilation context to
7
+ # add or remove things from the catalog.
8
+ #
9
+ # @api public
10
+ class CatalogCompiler < Compiler
11
+
12
+ # @api private
13
+ def catalog
14
+ internal_compiler.catalog
15
+ end
16
+ private :catalog
17
+
18
+ # Returns true if this is a compiler that compiles a catalog.
19
+ # This implementation returns `true`
20
+ # @return [Boolean] true
21
+ # @api public
22
+ def has_catalog?
23
+ true
24
+ end
25
+
26
+ # Calls a block of code and yields a configured `JsonCatalogEncoder` to the block.
27
+ # @example Get resulting catalog as pretty printed Json
28
+ # Puppet::Pal.in_environment(...) do |pal|
29
+ # pal.with_catalog_compiler(...) do |compiler|
30
+ # compiler.with_json_encoding {| encoder | encoder.encode
31
+ # end
32
+ # end
33
+ #
34
+ # @api public
35
+ #
36
+ def with_json_encoding(pretty: true, exclude_virtual: true)
37
+ yield JsonCatalogEncoder.new(catalog, pretty: pretty, exclude_virtual: exclude_virtual)
38
+ end
39
+
40
+ # Evaluates an AST obtained from `parse_string` or `parse_file` in topscope.
41
+ # If the ast is a `Puppet::Pops::Model::Program` (what is returned from the `parse` methods, any definitions
42
+ # in the program (that is, any function, plan, etc. that is defined will be made available for use).
43
+ #
44
+ # @param ast [Puppet::Pops::Model::PopsObject] typically the returned `Program` from the parse methods, but can be any `Expression`
45
+ # @returns [Object] whatever the ast evaluates to
46
+ #
47
+ def evaluate(ast)
48
+ if ast.is_a?(Puppet::Pops::Model::Program)
49
+ bridged = Puppet::Parser::AST::PopsBridge::Program.new(ast)
50
+ # define all catalog types
51
+ internal_compiler.environment.known_resource_types.import_ast(bridged, "")
52
+ bridged.evaluate(internal_compiler.topscope)
53
+ else
54
+ internal_evaluator.evaluate(topscope, ast)
55
+ end
56
+ end
57
+
58
+
59
+ # Compiles the result of additional evaluation taking place in a PAL catalog compilation.
60
+ # This will evaluate all lazy constructs until all have been evaluated, and will the validate
61
+ # the result.
62
+ #
63
+ # This should be called if evaluating string or files of puppet logic after the initial
64
+ # compilation taking place by giving PAL a manifest or code-string.
65
+ # This method should be called when a series of evaluation should have reached a
66
+ # valid state (there should be no dangling relationships (to resources that does not
67
+ # exist).
68
+ #
69
+ # As an alternative the methods `evaluate_additions` can be called without any
70
+ # requirements on consistency and then calling `validate` at the end.
71
+ #
72
+ # Can be called multiple times.
73
+ #
74
+ # @return [Void]
75
+ def compile_additions
76
+ internal_compiler.compile_additions
77
+ end
78
+
79
+ # Validates the state of the catalog (without performing evaluation of any elements
80
+ # requiring lazy evaluation. Can be called multiple times.
81
+ #
82
+ def validate
83
+ internal_compiler.validate
84
+ end
85
+
86
+ # Evaluates all lazy constructs that were produced as a side effect of evaluating puppet logic.
87
+ # Can be called multiple times.
88
+ #
89
+ def evaluate_additions
90
+ internal_compiler.evaluate_additions
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,221 @@
1
+ module Puppet
2
+ module Pal
3
+
4
+ # A configured compiler as obtained in the callback from `Puppet::Pal.with_script_compiler`.
5
+ # (Later, there may also be a catalog compiler available.)
6
+ #
7
+ class Compiler
8
+ attr_reader :internal_compiler
9
+ protected :internal_compiler
10
+
11
+ attr_reader :internal_evaluator
12
+ protected :internal_evaluator
13
+
14
+ def initialize(internal_compiler)
15
+ @internal_compiler = internal_compiler
16
+ @internal_evaluator = Puppet::Pops::Parser::EvaluatingParser.new
17
+ end
18
+
19
+ # Calls a function given by name with arguments specified in an `Array`, and optionally accepts a code block.
20
+ # @param function_name [String] the name of the function to call
21
+ # @param args [Object] the arguments to the function
22
+ # @param block [Proc] an optional callable block that is given to the called function
23
+ # @return [Object] what the called function returns
24
+ #
25
+ def call_function(function_name, *args, &block)
26
+ # TRANSLATORS: do not translate variable name strings in these assertions
27
+ Pal::assert_non_empty_string(function_name, 'function_name', false)
28
+ Pal::assert_type(Pal::T_ANY_ARRAY, args, 'args', false)
29
+ internal_evaluator.evaluator.external_call_function(function_name, args, topscope, &block)
30
+ end
31
+
32
+ # Returns a Puppet::Pal::FunctionSignature object or nil if function is not found
33
+ # The returned FunctionSignature has information about all overloaded signatures of the function
34
+ #
35
+ # @example using function_signature
36
+ # # returns true if 'myfunc' is callable with three integer arguments 1, 2, 3
37
+ # compiler.function_signature('myfunc').callable_with?([1,2,3])
38
+ #
39
+ # @param function_name [String] the name of the function to get a signature for
40
+ # @return [Puppet::Pal::FunctionSignature] a function signature, or nil if function not found
41
+ #
42
+ def function_signature(function_name)
43
+ loader = internal_compiler.loaders.private_environment_loader
44
+ if func = loader.load(:function, function_name)
45
+ return FunctionSignature.new(func.class)
46
+ end
47
+ # Could not find function
48
+ nil
49
+ end
50
+
51
+ # Returns an array of TypedName objects for all functions, optionally filtered by a regular expression.
52
+ # The returned array has more information than just the leaf name - the typical thing is to just get
53
+ # the name as showing the following example.
54
+ #
55
+ # Errors that occur during function discovery will either be logged as warnings or collected by the optional
56
+ # `error_collector` array. When provided, it will receive {Puppet::DataTypes::Error} instances describing
57
+ # each error in detail and no warnings will be logged.
58
+ #
59
+ # @example getting the names of all functions
60
+ # compiler.list_functions.map {|tn| tn.name }
61
+ #
62
+ # @param filter_regex [Regexp] an optional regexp that filters based on name (matching names are included in the result)
63
+ # @param error_collector [Array<Puppet::DataTypes::Error>] an optional array that will receive errors during load
64
+ # @return [Array<Puppet::Pops::Loader::TypedName>] an array of typed names
65
+ #
66
+ def list_functions(filter_regex = nil, error_collector = nil)
67
+ list_loadable_kind(:function, filter_regex, error_collector)
68
+ end
69
+
70
+ # Evaluates a string of puppet language code in top scope.
71
+ # A "source_file" reference to a source can be given - if not an actual file name, by convention the name should
72
+ # be bracketed with < > to indicate it is something symbolic; for example `<commandline>` if the string was given on the
73
+ # command line.
74
+ #
75
+ # If the given `puppet_code` is `nil` or an empty string, `nil` is returned, otherwise the result of evaluating the
76
+ # puppet language string. The given string must form a complete and valid expression/statement as an error is raised
77
+ # otherwise. That is, it is not possible to divide a compound expression by line and evaluate each line individually.
78
+ #
79
+ # @param puppet_code [String, nil] the puppet language code to evaluate, must be a complete expression/statement
80
+ # @param source_file [String, nil] an optional reference to a source (a file or symbolic name/location)
81
+ # @return [Object] what the `puppet_code` evaluates to
82
+ #
83
+ def evaluate_string(puppet_code, source_file = nil)
84
+ return nil if puppet_code.nil? || puppet_code == ''
85
+ unless puppet_code.is_a?(String)
86
+ raise ArgumentError, _("The argument 'puppet_code' must be a String, got %{type}") % { type: puppet_code.class }
87
+ end
88
+ evaluate(parse_string(puppet_code, source_file))
89
+ end
90
+
91
+ # Evaluates a puppet language file in top scope.
92
+ # The file must exist and contain valid puppet language code or an error is raised.
93
+ #
94
+ # @param file [Path, String] an absolute path to a file with puppet language code, must exist
95
+ # @return [Object] what the last evaluated expression in the file evaluated to
96
+ #
97
+ def evaluate_file(file)
98
+ evaluate(parse_file(file))
99
+ end
100
+
101
+ # Evaluates an AST obtained from `parse_string` or `parse_file` in topscope.
102
+ # If the ast is a `Puppet::Pops::Model::Program` (what is returned from the `parse` methods, any definitions
103
+ # in the program (that is, any function, plan, etc. that is defined will be made available for use).
104
+ #
105
+ # @param ast [Puppet::Pops::Model::PopsObject] typically the returned `Program` from the parse methods, but can be any `Expression`
106
+ # @returns [Object] whatever the ast evaluates to
107
+ #
108
+ def evaluate(ast)
109
+ if ast.is_a?(Puppet::Pops::Model::Program)
110
+ loaders = Puppet.lookup(:loaders)
111
+ loaders.instantiate_definitions(ast, loaders.public_environment_loader)
112
+ end
113
+ internal_evaluator.evaluate(topscope, ast)
114
+ end
115
+
116
+ # Produces a literal value if the AST obtained from `parse_string` or `parse_file` does not require any actual evaluation.
117
+ # This method is useful if obtaining an AST that represents literal values; string, integer, float, boolean, regexp, array, hash;
118
+ # for example from having read this from the command line or as values in some file.
119
+ #
120
+ # @param ast [Puppet::Pops::Model::PopsObject] typically the returned `Program` from the parse methods, but can be any `Expression`
121
+ # @returns [Object] whatever the literal value the ast evaluates to
122
+ #
123
+ def evaluate_literal(ast)
124
+ catch :not_literal do
125
+ return Puppet::Pops::Evaluator::LiteralEvaluator.new().literal(ast)
126
+ end
127
+ # TRANSLATORS, the 'ast' is the name of a parameter, do not translate
128
+ raise ArgumentError, _("The given 'ast' does not represent a literal value")
129
+ end
130
+
131
+ # Parses and validates a puppet language string and returns an instance of Puppet::Pops::Model::Program on success.
132
+ # If the content is not valid an error is raised.
133
+ #
134
+ # @param code_string [String] a puppet language string to parse and validate
135
+ # @param source_file [String] an optional reference to a file or other location in angled brackets
136
+ # @return [Puppet::Pops::Model::Program] returns a `Program` instance on success
137
+ #
138
+ def parse_string(code_string, source_file = nil)
139
+ unless code_string.is_a?(String)
140
+ raise ArgumentError, _("The argument 'code_string' must be a String, got %{type}") % { type: code_string.class }
141
+ end
142
+ internal_evaluator.parse_string(code_string, source_file)
143
+ end
144
+
145
+ # Parses and validates a puppet language file and returns an instance of Puppet::Pops::Model::Program on success.
146
+ # If the content is not valid an error is raised.
147
+ #
148
+ # @param file [String] a file with puppet language content to parse and validate
149
+ # @return [Puppet::Pops::Model::Program] returns a `Program` instance on success
150
+ #
151
+ def parse_file(file)
152
+ unless file.is_a?(String)
153
+ raise ArgumentError, _("The argument 'file' must be a String, got %{type}") % { type: file.class }
154
+ end
155
+ internal_evaluator.parse_file(file)
156
+ end
157
+
158
+ # Parses a puppet data type given in String format and returns that type, or raises an error.
159
+ # A type is needed in calls to `new` to create an instance of the data type, or to perform type checking
160
+ # of values - typically using `type.instance?(obj)` to check if `obj` is an instance of the type.
161
+ #
162
+ # @example Verify if obj is an instance of a data type
163
+ # # evaluates to true
164
+ # pal.type('Enum[red, blue]').instance?("blue")
165
+ #
166
+ # @example Create an instance of a data type
167
+ # # using an already create type
168
+ # t = pal.type('Car')
169
+ # pal.create(t, 'color' => 'black', 'make' => 't-ford')
170
+ #
171
+ # # letting 'new_object' parse the type from a string
172
+ # pal.create('Car', 'color' => 'black', 'make' => 't-ford')
173
+ #
174
+ # @param type_string [String] a puppet language data type
175
+ # @return [Puppet::Pops::Types::PAnyType] the data type
176
+ #
177
+ def type(type_string)
178
+ Puppet::Pops::Types::TypeParser.singleton.parse(type_string)
179
+ end
180
+
181
+ # Creates a new instance of a given data type.
182
+ # @param data_type [String, Puppet::Pops::Types::PAnyType] the data type as a data type or in String form.
183
+ # @param arguments [Object] one or more arguments to the called `new` function
184
+ # @return [Object] an instance of the given data type,
185
+ # or raises an error if it was not possible to parse data type or create an instance.
186
+ #
187
+ def create(data_type, *arguments)
188
+ t = data_type.is_a?(String) ? type(data_type) : data_type
189
+ unless t.is_a?(Puppet::Pops::Types::PAnyType)
190
+ raise ArgumentError, _("Given data_type value is not a data type, got '%{type}'") % {type: t.class}
191
+ end
192
+ call_function('new', t, *arguments)
193
+ end
194
+
195
+ # Returns true if this is a compiler that compiles a catalog.
196
+ # This implementation returns `false`
197
+ # @return Boolan false
198
+ def has_catalog?
199
+ false
200
+ end
201
+
202
+ protected
203
+
204
+ def list_loadable_kind(kind, filter_regex = nil, error_collector = nil)
205
+ loader = internal_compiler.loaders.private_environment_loader
206
+ if filter_regex.nil?
207
+ loader.discover(kind, error_collector)
208
+ else
209
+ loader.discover(kind, error_collector) {|f| f.name =~ filter_regex }
210
+ end
211
+ end
212
+
213
+ private
214
+
215
+ def topscope
216
+ internal_compiler.topscope
217
+ end
218
+ end
219
+
220
+ end
221
+ end
@@ -0,0 +1,52 @@
1
+ module Puppet
2
+ module Pal
3
+ # A FunctionSignature is returned from `function_signature`. Its purpose is to answer questions about the function's parameters
4
+ # and if it can be called with a set of parameters.
5
+ #
6
+ # It is also possible to get an array of puppet Callable data type where each callable describes one possible way
7
+ # the function can be called.
8
+ #
9
+ # @api public
10
+ #
11
+ class FunctionSignature
12
+ # @api private
13
+ def initialize(function_class)
14
+ @func = function_class
15
+ end
16
+
17
+ # Returns true if the function can be called with the given arguments and false otherwise.
18
+ # If the function is not callable, and a code block is given, it is given a formatted error message that describes
19
+ # the type mismatch. That error message can be quite complex if the function has multiple dispatch depending on
20
+ # given types.
21
+ #
22
+ # @param args [Array] The arguments as given to the function call
23
+ # @param callable [Proc, nil] An optional ruby Proc or puppet lambda given to the function
24
+ # @yield [String] a formatted error message describing a type mismatch if the function is not callable with given args + block
25
+ # @return [Boolean] true if the function can be called with given args + block, and false otherwise
26
+ # @api public
27
+ #
28
+ def callable_with?(args, callable=nil)
29
+ signatures = @func.dispatcher.to_type
30
+ callables = signatures.is_a?(Puppet::Pops::Types::PVariantType) ? signatures.types : [signatures]
31
+
32
+ return true if callables.any? {|t| t.callable_with?(args) }
33
+ return false unless block_given?
34
+ args_type = Puppet::Pops::Types::TypeCalculator.singleton.infer_set(callable.nil? ? args : args + [callable])
35
+ error_message = Puppet::Pops::Types::TypeMismatchDescriber.describe_signatures(@func.name, @func.signatures, args_type)
36
+ yield error_message
37
+ false
38
+ end
39
+
40
+ # Returns an array of Callable puppet data type
41
+ # @return [Array<Puppet::Pops::Types::PCallableType] one callable per way the function can be called
42
+ #
43
+ # @api public
44
+ #
45
+ def callables
46
+ signatures = @func.dispatcher.to_type
47
+ signatures.is_a?(Puppet::Pops::Types::PVariantType) ? signatures.types : [signatures]
48
+ end
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,67 @@
1
+ # The JsonCatalogEncoder is a wrapper around a catalog produced by the Pal::CatalogCompiler.with_json_encoding
2
+ # method.
3
+ # It allows encoding the entire catalog or an individual resource as Rich Data Json.
4
+ #
5
+ # @api public
6
+ #
7
+ class JsonCatalogEncoder
8
+ # Is the resulting Json pretty printed or not.
9
+ attr_reader :pretty
10
+
11
+ # Should unrealized virtual resources be included in the result or not.
12
+ attr_reader :exclude_virtual
13
+
14
+ # The internal catalog being build - what this class wraps with a public API.
15
+ attr_reader :catalog
16
+ private :catalog
17
+
18
+ # Do not instantiate this class directly! Use the `Pal::CatalogCompiler#with_json_encoding` method
19
+ # instead.
20
+ #
21
+ # @param catalog [Puppet::Resource::Catalog] the internal catalog that this class wraps
22
+ # @param pretty [Boolean] (true), if the resulting JSON should be pretty printed or not
23
+ # @param exclude_virtual [Boolean] (true), if the resulting catalog should contain unrealzed virtual resources or not
24
+ #
25
+ # @api private
26
+ #
27
+ def initialize(catalog, pretty: true, exclude_virtual: true)
28
+ @catalog = catalog
29
+ @pretty = pretty
30
+ @exclude_virtual = exclude_virtual
31
+ end
32
+
33
+ # Encodes the entire catalog as a rich-data Json catalog.
34
+ # @return String The catalog in Json format using rich data format
35
+ # @api public
36
+ #
37
+ def encode
38
+ possibly_filtered_catalog.to_json(:pretty => pretty)
39
+ end
40
+
41
+ # Returns one particular resource as a Json string, or returns nil if resource was not found.
42
+ # @param type [String] the name of the puppet type (case independent)
43
+ # @param title [String] the title of the wanted resource
44
+ # @return [String] the resulting Json text
45
+ # @api public
46
+ #
47
+ def encode_resource(type, title)
48
+ # Ensure that both type and title are given since the underlying API will do mysterious things
49
+ # if 'title' is nil. (Other assertions are made by the catalog when looking up the resource).
50
+ #
51
+ # TRANSLATORS 'type' and 'title' are internal parameter names - do not translate
52
+ raise ArgumentError, _("Both type and title must be given") if type.nil? or title.nil?
53
+ r = possibly_filtered_catalog.resource(type, title)
54
+ return nil if r.nil?
55
+ r.to_data_hash.to_json(:pretty => pretty)
56
+ end
57
+
58
+ # Applies a filter for virtual resources and returns filtered catalog
59
+ # or the catalog itself if filtering was not needed.
60
+ # The result is cached.
61
+ # @api private
62
+ #
63
+ def possibly_filtered_catalog
64
+ @filtered ||= (exclude_virtual ? catalog.filter { |r| r.virtual? } : catalog)
65
+ end
66
+ private :possibly_filtered_catalog
67
+ end
@@ -0,0 +1,15 @@
1
+ module Puppet
2
+ require 'puppet/parser/script_compiler'
3
+ require 'puppet/parser/catalog_compiler'
4
+
5
+ module Pal
6
+ require 'puppet/pal/json_catalog_encoder'
7
+ require 'puppet/pal/function_signature'
8
+ require 'puppet/pal/task_signature'
9
+ require 'puppet/pal/plan_signature'
10
+ require 'puppet/pal/compiler'
11
+ require 'puppet/pal/script_compiler'
12
+ require 'puppet/pal/catalog_compiler'
13
+ require 'puppet/pal/pal_impl'
14
+ end
15
+ end