openbolt 5.0.0.rc1

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 (258) hide show
  1. checksums.yaml +7 -0
  2. data/Puppetfile +52 -0
  3. data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +60 -0
  4. data/bolt-modules/boltlib/lib/puppet/datatypes/containerresult.rb +51 -0
  5. data/bolt-modules/boltlib/lib/puppet/datatypes/future.rb +25 -0
  6. data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +71 -0
  7. data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +55 -0
  8. data/bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb +65 -0
  9. data/bolt-modules/boltlib/lib/puppet/datatypes/target.rb +93 -0
  10. data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +33 -0
  11. data/bolt-modules/boltlib/lib/puppet/functions/add_to_group.rb +38 -0
  12. data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +208 -0
  13. data/bolt-modules/boltlib/lib/puppet/functions/background.rb +62 -0
  14. data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +57 -0
  15. data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +130 -0
  16. data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +31 -0
  17. data/bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb +52 -0
  18. data/bolt-modules/boltlib/lib/puppet/functions/get_resources.rb +87 -0
  19. data/bolt-modules/boltlib/lib/puppet/functions/get_target.rb +34 -0
  20. data/bolt-modules/boltlib/lib/puppet/functions/get_targets.rb +35 -0
  21. data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +74 -0
  22. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_command.rb +97 -0
  23. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb +47 -0
  24. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +52 -0
  25. data/bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb +40 -0
  26. data/bolt-modules/boltlib/lib/puppet/functions/resolve_references.rb +42 -0
  27. data/bolt-modules/boltlib/lib/puppet/functions/resource.rb +53 -0
  28. data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +106 -0
  29. data/bolt-modules/boltlib/lib/puppet/functions/run_container.rb +162 -0
  30. data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +291 -0
  31. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +145 -0
  32. data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +164 -0
  33. data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +211 -0
  34. data/bolt-modules/boltlib/lib/puppet/functions/set_config.rb +48 -0
  35. data/bolt-modules/boltlib/lib/puppet/functions/set_feature.rb +43 -0
  36. data/bolt-modules/boltlib/lib/puppet/functions/set_resources.rb +145 -0
  37. data/bolt-modules/boltlib/lib/puppet/functions/set_var.rb +38 -0
  38. data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +101 -0
  39. data/bolt-modules/boltlib/lib/puppet/functions/vars.rb +29 -0
  40. data/bolt-modules/boltlib/lib/puppet/functions/wait.rb +131 -0
  41. data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +59 -0
  42. data/bolt-modules/boltlib/lib/puppet/functions/without_default_logging.rb +39 -0
  43. data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +50 -0
  44. data/bolt-modules/boltlib/types/planresult.pp +18 -0
  45. data/bolt-modules/boltlib/types/targetspec.pp +7 -0
  46. data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +42 -0
  47. data/bolt-modules/ctrl/lib/puppet/functions/ctrl/sleep.rb +20 -0
  48. data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +35 -0
  49. data/bolt-modules/file/lib/puppet/functions/file/delete.rb +21 -0
  50. data/bolt-modules/file/lib/puppet/functions/file/exists.rb +28 -0
  51. data/bolt-modules/file/lib/puppet/functions/file/join.rb +20 -0
  52. data/bolt-modules/file/lib/puppet/functions/file/read.rb +33 -0
  53. data/bolt-modules/file/lib/puppet/functions/file/readable.rb +28 -0
  54. data/bolt-modules/file/lib/puppet/functions/file/write.rb +24 -0
  55. data/bolt-modules/log/lib/puppet/functions/log/debug.rb +39 -0
  56. data/bolt-modules/log/lib/puppet/functions/log/error.rb +40 -0
  57. data/bolt-modules/log/lib/puppet/functions/log/fatal.rb +40 -0
  58. data/bolt-modules/log/lib/puppet/functions/log/info.rb +39 -0
  59. data/bolt-modules/log/lib/puppet/functions/log/trace.rb +39 -0
  60. data/bolt-modules/log/lib/puppet/functions/log/warn.rb +41 -0
  61. data/bolt-modules/out/lib/puppet/functions/out/message.rb +36 -0
  62. data/bolt-modules/out/lib/puppet/functions/out/verbose.rb +35 -0
  63. data/bolt-modules/prompt/lib/puppet/functions/prompt/menu.rb +103 -0
  64. data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +65 -0
  65. data/bolt-modules/system/lib/puppet/functions/system/env.rb +20 -0
  66. data/exe/bolt +17 -0
  67. data/guides/debugging.yaml +27 -0
  68. data/guides/inventory.yaml +23 -0
  69. data/guides/links.yaml +12 -0
  70. data/guides/logging.yaml +17 -0
  71. data/guides/module.yaml +18 -0
  72. data/guides/modulepath.yaml +24 -0
  73. data/guides/project.yaml +21 -0
  74. data/guides/targets.yaml +28 -0
  75. data/guides/transports.yaml +22 -0
  76. data/lib/bolt/analytics.rb +233 -0
  77. data/lib/bolt/application.rb +806 -0
  78. data/lib/bolt/applicator.rb +368 -0
  79. data/lib/bolt/apply_inventory.rb +93 -0
  80. data/lib/bolt/apply_result.rb +154 -0
  81. data/lib/bolt/apply_target.rb +90 -0
  82. data/lib/bolt/bolt_option_parser.rb +1226 -0
  83. data/lib/bolt/catalog/logging.rb +15 -0
  84. data/lib/bolt/catalog.rb +144 -0
  85. data/lib/bolt/cli.rb +949 -0
  86. data/lib/bolt/config/modulepath.rb +30 -0
  87. data/lib/bolt/config/options.rb +673 -0
  88. data/lib/bolt/config/transport/base.rb +133 -0
  89. data/lib/bolt/config/transport/docker.rb +34 -0
  90. data/lib/bolt/config/transport/jail.rb +33 -0
  91. data/lib/bolt/config/transport/local.rb +39 -0
  92. data/lib/bolt/config/transport/lxd.rb +34 -0
  93. data/lib/bolt/config/transport/options.rb +431 -0
  94. data/lib/bolt/config/transport/orch.rb +41 -0
  95. data/lib/bolt/config/transport/podman.rb +33 -0
  96. data/lib/bolt/config/transport/remote.rb +24 -0
  97. data/lib/bolt/config/transport/ssh.rb +138 -0
  98. data/lib/bolt/config/transport/winrm.rb +63 -0
  99. data/lib/bolt/config.rb +515 -0
  100. data/lib/bolt/container_result.rb +105 -0
  101. data/lib/bolt/error.rb +194 -0
  102. data/lib/bolt/executor.rb +539 -0
  103. data/lib/bolt/fiber_executor.rb +190 -0
  104. data/lib/bolt/inventory/group.rb +446 -0
  105. data/lib/bolt/inventory/inventory.rb +391 -0
  106. data/lib/bolt/inventory/options.rb +139 -0
  107. data/lib/bolt/inventory/target.rb +293 -0
  108. data/lib/bolt/inventory.rb +120 -0
  109. data/lib/bolt/logger.rb +252 -0
  110. data/lib/bolt/module.rb +54 -0
  111. data/lib/bolt/module_installer/installer.rb +44 -0
  112. data/lib/bolt/module_installer/puppetfile/forge_module.rb +54 -0
  113. data/lib/bolt/module_installer/puppetfile/git_module.rb +37 -0
  114. data/lib/bolt/module_installer/puppetfile/module.rb +26 -0
  115. data/lib/bolt/module_installer/puppetfile.rb +131 -0
  116. data/lib/bolt/module_installer/resolver.rb +129 -0
  117. data/lib/bolt/module_installer/specs/forge_spec.rb +91 -0
  118. data/lib/bolt/module_installer/specs/git_spec.rb +150 -0
  119. data/lib/bolt/module_installer/specs/id/base.rb +116 -0
  120. data/lib/bolt/module_installer/specs/id/gitclone.rb +120 -0
  121. data/lib/bolt/module_installer/specs/id/github.rb +90 -0
  122. data/lib/bolt/module_installer/specs/id/gitlab.rb +92 -0
  123. data/lib/bolt/module_installer/specs.rb +95 -0
  124. data/lib/bolt/module_installer.rb +208 -0
  125. data/lib/bolt/node/errors.rb +55 -0
  126. data/lib/bolt/node/output.rb +29 -0
  127. data/lib/bolt/outputter/human.rb +958 -0
  128. data/lib/bolt/outputter/json.rb +205 -0
  129. data/lib/bolt/outputter/logger.rb +76 -0
  130. data/lib/bolt/outputter/rainbow.rb +118 -0
  131. data/lib/bolt/outputter.rb +57 -0
  132. data/lib/bolt/pal/issues.rb +19 -0
  133. data/lib/bolt/pal/logging.rb +17 -0
  134. data/lib/bolt/pal/yaml_plan/evaluator.rb +83 -0
  135. data/lib/bolt/pal/yaml_plan/loader.rb +94 -0
  136. data/lib/bolt/pal/yaml_plan/parameter.rb +63 -0
  137. data/lib/bolt/pal/yaml_plan/step/command.rb +45 -0
  138. data/lib/bolt/pal/yaml_plan/step/download.rb +37 -0
  139. data/lib/bolt/pal/yaml_plan/step/eval.rb +42 -0
  140. data/lib/bolt/pal/yaml_plan/step/message.rb +31 -0
  141. data/lib/bolt/pal/yaml_plan/step/plan.rb +42 -0
  142. data/lib/bolt/pal/yaml_plan/step/resources.rb +170 -0
  143. data/lib/bolt/pal/yaml_plan/step/script.rb +62 -0
  144. data/lib/bolt/pal/yaml_plan/step/task.rb +42 -0
  145. data/lib/bolt/pal/yaml_plan/step/upload.rb +37 -0
  146. data/lib/bolt/pal/yaml_plan/step/verbose.rb +31 -0
  147. data/lib/bolt/pal/yaml_plan/step.rb +223 -0
  148. data/lib/bolt/pal/yaml_plan/transpiler.rb +90 -0
  149. data/lib/bolt/pal/yaml_plan.rb +172 -0
  150. data/lib/bolt/pal.rb +847 -0
  151. data/lib/bolt/plan_creator.rb +219 -0
  152. data/lib/bolt/plan_future.rb +86 -0
  153. data/lib/bolt/plan_result.rb +44 -0
  154. data/lib/bolt/plugin/cache.rb +76 -0
  155. data/lib/bolt/plugin/env_var.rb +54 -0
  156. data/lib/bolt/plugin/module.rb +276 -0
  157. data/lib/bolt/plugin/prompt.rb +36 -0
  158. data/lib/bolt/plugin/puppet_connect_data.rb +84 -0
  159. data/lib/bolt/plugin/puppetdb.rb +124 -0
  160. data/lib/bolt/plugin/task.rb +72 -0
  161. data/lib/bolt/plugin.rb +380 -0
  162. data/lib/bolt/project.rb +219 -0
  163. data/lib/bolt/project_manager/config_migrator.rb +113 -0
  164. data/lib/bolt/project_manager/inventory_migrator.rb +67 -0
  165. data/lib/bolt/project_manager/migrator.rb +39 -0
  166. data/lib/bolt/project_manager/module_migrator.rb +203 -0
  167. data/lib/bolt/project_manager.rb +221 -0
  168. data/lib/bolt/puppetdb/client.rb +153 -0
  169. data/lib/bolt/puppetdb/config.rb +176 -0
  170. data/lib/bolt/puppetdb/instance.rb +146 -0
  171. data/lib/bolt/puppetdb.rb +15 -0
  172. data/lib/bolt/r10k_log_proxy.rb +30 -0
  173. data/lib/bolt/rerun.rb +55 -0
  174. data/lib/bolt/resource_instance.rb +133 -0
  175. data/lib/bolt/result.rb +247 -0
  176. data/lib/bolt/result_set.rb +128 -0
  177. data/lib/bolt/shell/bash/tmpdir.rb +62 -0
  178. data/lib/bolt/shell/bash.rb +516 -0
  179. data/lib/bolt/shell/powershell/snippets.rb +181 -0
  180. data/lib/bolt/shell/powershell.rb +365 -0
  181. data/lib/bolt/shell.rb +105 -0
  182. data/lib/bolt/target.rb +174 -0
  183. data/lib/bolt/task/puppet_server.rb +27 -0
  184. data/lib/bolt/task/run.rb +55 -0
  185. data/lib/bolt/task.rb +163 -0
  186. data/lib/bolt/transport/base.rb +252 -0
  187. data/lib/bolt/transport/docker/connection.rb +150 -0
  188. data/lib/bolt/transport/docker.rb +23 -0
  189. data/lib/bolt/transport/jail/connection.rb +81 -0
  190. data/lib/bolt/transport/jail.rb +21 -0
  191. data/lib/bolt/transport/local/connection.rb +106 -0
  192. data/lib/bolt/transport/local.rb +20 -0
  193. data/lib/bolt/transport/lxd/connection.rb +115 -0
  194. data/lib/bolt/transport/lxd.rb +26 -0
  195. data/lib/bolt/transport/orch/connection.rb +111 -0
  196. data/lib/bolt/transport/orch.rb +271 -0
  197. data/lib/bolt/transport/podman/connection.rb +102 -0
  198. data/lib/bolt/transport/podman.rb +19 -0
  199. data/lib/bolt/transport/remote.rb +41 -0
  200. data/lib/bolt/transport/simple.rb +54 -0
  201. data/lib/bolt/transport/ssh/connection.rb +321 -0
  202. data/lib/bolt/transport/ssh/exec_connection.rb +140 -0
  203. data/lib/bolt/transport/ssh.rb +48 -0
  204. data/lib/bolt/transport/winrm/connection.rb +378 -0
  205. data/lib/bolt/transport/winrm.rb +33 -0
  206. data/lib/bolt/util/format.rb +68 -0
  207. data/lib/bolt/util/puppet_log_level.rb +21 -0
  208. data/lib/bolt/util.rb +465 -0
  209. data/lib/bolt/validator.rb +227 -0
  210. data/lib/bolt/version.rb +5 -0
  211. data/lib/bolt.rb +8 -0
  212. data/lib/bolt_server/acl.rb +39 -0
  213. data/lib/bolt_server/base_config.rb +112 -0
  214. data/lib/bolt_server/config.rb +64 -0
  215. data/lib/bolt_server/file_cache.rb +200 -0
  216. data/lib/bolt_server/request_error.rb +11 -0
  217. data/lib/bolt_server/schemas/action-check_node_connections.json +14 -0
  218. data/lib/bolt_server/schemas/action-run_command.json +12 -0
  219. data/lib/bolt_server/schemas/action-run_script.json +47 -0
  220. data/lib/bolt_server/schemas/action-run_task.json +20 -0
  221. data/lib/bolt_server/schemas/action-upload_file.json +47 -0
  222. data/lib/bolt_server/schemas/partials/target-any.json +10 -0
  223. data/lib/bolt_server/schemas/partials/target-ssh.json +88 -0
  224. data/lib/bolt_server/schemas/partials/target-winrm.json +67 -0
  225. data/lib/bolt_server/schemas/partials/task.json +94 -0
  226. data/lib/bolt_server/schemas/transport-ssh.json +25 -0
  227. data/lib/bolt_server/schemas/transport-winrm.json +19 -0
  228. data/lib/bolt_server/transport_app.rb +554 -0
  229. data/lib/bolt_spec/bolt_context.rb +226 -0
  230. data/lib/bolt_spec/plans/action_stubs/command_stub.rb +51 -0
  231. data/lib/bolt_spec/plans/action_stubs/download_stub.rb +66 -0
  232. data/lib/bolt_spec/plans/action_stubs/plan_stub.rb +55 -0
  233. data/lib/bolt_spec/plans/action_stubs/script_stub.rb +59 -0
  234. data/lib/bolt_spec/plans/action_stubs/task_stub.rb +57 -0
  235. data/lib/bolt_spec/plans/action_stubs/upload_stub.rb +65 -0
  236. data/lib/bolt_spec/plans/action_stubs.rb +196 -0
  237. data/lib/bolt_spec/plans/mock_executor.rb +361 -0
  238. data/lib/bolt_spec/plans/publish_stub.rb +49 -0
  239. data/lib/bolt_spec/plans.rb +190 -0
  240. data/lib/bolt_spec/run.rb +246 -0
  241. data/lib/logging_extensions/logging.rb +13 -0
  242. data/libexec/apply_catalog.rb +130 -0
  243. data/libexec/bolt_catalog +68 -0
  244. data/libexec/custom_facts.rb +63 -0
  245. data/libexec/query_resources.rb +75 -0
  246. data/modules/aggregate/lib/puppet/functions/aggregate/count.rb +21 -0
  247. data/modules/aggregate/lib/puppet/functions/aggregate/nodes.rb +22 -0
  248. data/modules/aggregate/lib/puppet/functions/aggregate/targets.rb +21 -0
  249. data/modules/aggregate/plans/count.pp +56 -0
  250. data/modules/aggregate/plans/targets.pp +56 -0
  251. data/modules/canary/lib/puppet/functions/canary/merge.rb +13 -0
  252. data/modules/canary/lib/puppet/functions/canary/random_split.rb +22 -0
  253. data/modules/canary/lib/puppet/functions/canary/skip.rb +25 -0
  254. data/modules/canary/plans/init.pp +100 -0
  255. data/modules/puppet_connect/plans/test_input_data.pp +94 -0
  256. data/modules/puppetdb_fact/plans/init.pp +20 -0
  257. data/resources/bolt_bash_completion.sh +214 -0
  258. metadata +735 -0
@@ -0,0 +1,205 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../bolt/util/format'
4
+
5
+ module Bolt
6
+ class Outputter
7
+ class JSON < Bolt::Outputter
8
+ def initialize(color, verbose, trace, spin, stream = $stdout)
9
+ super
10
+ @items_open = false
11
+ @object_open = false
12
+ @preceding_item = false
13
+ end
14
+
15
+ def print_head
16
+ @stream.puts '{ "items": ['
17
+ @preceding_item = false
18
+ @items_open = true
19
+ @object_open = true
20
+ end
21
+
22
+ def handle_event(event)
23
+ case event[:type]
24
+ when :node_result
25
+ print_result(event[:result])
26
+ when :message
27
+ print_message(event[:message])
28
+ when :verbose
29
+ print_message(event[:message]) if @verbose
30
+ end
31
+ end
32
+
33
+ def print_result(result)
34
+ @stream.puts ',' if @preceding_item
35
+ @stream.puts result.to_json
36
+ @preceding_item = true
37
+ end
38
+
39
+ def print_summary(results, elapsed_time)
40
+ @stream.puts "],\n"
41
+ @preceding_item = false
42
+ @items_open = false
43
+ @stream.puts format('"target_count": %<size>d, "elapsed_time": %<elapsed>d }',
44
+ size: results.size,
45
+ elapsed: elapsed_time)
46
+ end
47
+
48
+ def print_table(results)
49
+ @stream.puts results.to_json
50
+ end
51
+ alias print_module_list print_table
52
+ alias print_module_info print_table
53
+
54
+ # Print information about a task.
55
+ #
56
+ # @param task [Bolt::Task] The task information.
57
+ #
58
+ def print_task_info(task:)
59
+ path = task.files.first['path'].chomp("/tasks/#{task.files.first['name']}")
60
+ module_dir = if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
61
+ "built-in module"
62
+ else
63
+ path
64
+ end
65
+ @stream.puts task.to_h.merge(module_dir: module_dir).to_json
66
+ end
67
+
68
+ # List available tasks.
69
+ #
70
+ # @param tasks [Array] A list of task names and descriptions.
71
+ # @param modulepath [Array] The modulepath.
72
+ #
73
+ def print_tasks(**kwargs)
74
+ print_table(**kwargs)
75
+ end
76
+
77
+ def print_plugin_list(plugins:, modulepath:)
78
+ plugins.delete(:validate_resolve_reference)
79
+ print_table('plugins' => plugins, 'modulepath' => modulepath)
80
+ end
81
+
82
+ def print_plan_info(plan)
83
+ path = plan.delete('module')
84
+ plan['module_dir'] = if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
85
+ "built-in module"
86
+ else
87
+ path
88
+ end
89
+ @stream.puts plan.to_json
90
+ end
91
+
92
+ def print_policy_list(**kwargs)
93
+ print_table(**kwargs)
94
+ end
95
+
96
+ def print_plans(**kwargs)
97
+ print_table(**kwargs)
98
+ end
99
+
100
+ def print_new_plan(**kwargs)
101
+ print_table(**kwargs)
102
+ end
103
+
104
+ def print_new_policy(**kwargs)
105
+ print_table(**kwargs)
106
+ end
107
+
108
+ def print_apply_result(apply_result)
109
+ @stream.puts apply_result.to_json
110
+ end
111
+
112
+ def print_plan_result(result)
113
+ # Ruby JSON patches most objects to have a to_json method.
114
+ @stream.puts result.to_json
115
+ end
116
+
117
+ def print_result_set(result_set)
118
+ @stream.puts result_set.to_json
119
+ end
120
+
121
+ # Print available guide topics.
122
+ #
123
+ # @param topics [Array] The available topics.
124
+ #
125
+ def print_topics(**kwargs)
126
+ print_table(kwargs)
127
+ end
128
+
129
+ # Print the guide for the specified topic.
130
+ #
131
+ # @param guide [String] The guide.
132
+ # @param topic [String] The topic.
133
+ #
134
+ def print_guide(**kwargs)
135
+ @stream.puts(kwargs.to_json)
136
+ end
137
+
138
+ def print_plan_lookup(value)
139
+ @stream.puts(value.to_json)
140
+ end
141
+
142
+ def print_puppetfile_result(success, puppetfile, moduledir)
143
+ @stream.puts({ success: success,
144
+ puppetfile: puppetfile,
145
+ moduledir: moduledir.to_s }.to_json)
146
+ end
147
+
148
+ # Print target names and where they came from.
149
+ #
150
+ # @param adhoc [Hash] Adhoc targets provided on the command line.
151
+ # @param inventory [Hash] Targets provided from the inventory.
152
+ # @param targets [Array] All targets.
153
+ # @param count [Integer] Number of targets.
154
+ #
155
+ def print_targets(adhoc:, inventory:, targets:, count:, **_kwargs)
156
+ adhoc[:targets] = adhoc[:targets].map { |t| t['name'] }
157
+ inventory[:targets] = inventory[:targets].map { |t| t['name'] }
158
+ targets = targets.map { |t| t['name'] }
159
+ @stream.puts({ adhoc: adhoc, inventory: inventory, targets: targets, count: count }.to_json)
160
+ end
161
+
162
+ # Print target names and where they came from.
163
+ #
164
+ # @param adhoc [Hash] Adhoc targets provided on the command line.
165
+ # @param inventory [Hash] Targets provided from the inventory.
166
+ # @param targets [Array] All targets.
167
+ # @param count [Integer] Number of targets.
168
+ #
169
+ def print_target_info(adhoc:, inventory:, targets:, count:, **_kwargs)
170
+ @stream.puts({ adhoc: adhoc, inventory: inventory, targets: targets, count: count }.to_json)
171
+ end
172
+
173
+ # Print inventory group information.
174
+ #
175
+ # @param count [Integer] Number of groups in the inventory.
176
+ # @param groups [Array] Names of groups in the inventory.
177
+ #
178
+ def print_groups(count:, groups:, **_kwargs)
179
+ @stream.puts({ count: count, groups: groups }.to_json)
180
+ end
181
+
182
+ def fatal_error(err)
183
+ @stream.puts "],\n" if @items_open
184
+ @stream.puts '"_error": ' if @object_open
185
+ err_obj = err.to_h
186
+ if @trace && err.backtrace
187
+ err_obj[:details] ||= {}
188
+ err_obj[:details][:backtrace] = err.backtrace
189
+ end
190
+ @stream.puts err_obj.to_json
191
+ @stream.puts '}' if @object_open
192
+ end
193
+
194
+ def print_message(message)
195
+ $stderr.puts(Bolt::Util::Format.stringify(message))
196
+ end
197
+ alias print_error print_message
198
+
199
+ def print_action_step(step)
200
+ $stderr.puts(step)
201
+ end
202
+ alias print_action_error print_action_step
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../bolt/pal'
4
+
5
+ module Bolt
6
+ class Outputter
7
+ class Logger < Bolt::Outputter
8
+ def initialize(verbose, trace)
9
+ super(false, verbose, trace, false)
10
+ @logger = Bolt::Logger.logger(self)
11
+ end
12
+
13
+ def handle_event(event)
14
+ case event[:type]
15
+ when :step_start
16
+ log_step_start(**event)
17
+ when :step_finish
18
+ log_step_finish(**event)
19
+ when :plan_start
20
+ log_plan_start(event)
21
+ when :plan_finish
22
+ log_plan_finish(event)
23
+ when :container_start
24
+ log_container_start(event)
25
+ when :container_finish
26
+ log_container_finish(event)
27
+ when :log, :message, :verbose
28
+ log_message(**event)
29
+ end
30
+ end
31
+
32
+ def log_step_start(description:, targets:, **_kwargs)
33
+ target_str = if targets.length > 5
34
+ "#{targets.count} targets"
35
+ else
36
+ targets.map(&:safe_name).join(', ')
37
+ end
38
+ @logger.info("Starting: #{description} on #{target_str}")
39
+ end
40
+
41
+ def log_step_finish(description:, result:, duration:, **_kwargs)
42
+ failures = result.error_set.length
43
+ plural = failures == 1 ? '' : 's'
44
+ @logger.info("Finished: #{description} with #{failures} failure#{plural} in #{duration.round(2)} sec")
45
+ end
46
+
47
+ def log_plan_start(event)
48
+ plan = event[:plan]
49
+ @logger.info("Starting: plan #{plan}")
50
+ end
51
+
52
+ def log_plan_finish(event)
53
+ plan = event[:plan]
54
+ duration = event[:duration]
55
+ @logger.info("Finished: plan #{plan} in #{duration.round(2)} sec")
56
+ end
57
+
58
+ def log_container_start(event)
59
+ @logger.info("Starting: run container '#{event[:image]}'")
60
+ end
61
+
62
+ def log_container_finish(event)
63
+ result = event[:result]
64
+ if result.success?
65
+ @logger.info("Finished: run container '#{result.object}' succeeded.")
66
+ else
67
+ @logger.info("Finished: run container '#{result.object}' failed.")
68
+ end
69
+ end
70
+
71
+ def log_message(level:, message:, **_kwargs)
72
+ @logger.send(level, message)
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../bolt/pal'
4
+ require_relative '../../bolt/util/format'
5
+
6
+ module Bolt
7
+ class Outputter
8
+ class Rainbow < Bolt::Outputter::Human
9
+ def initialize(color, verbose, trace, spin, stream = $stdout)
10
+ begin
11
+ require 'paint'
12
+ if Bolt::Util.windows?
13
+ # the Paint gem thinks that windows does not support ansi colors
14
+ # but windows 10 or later does
15
+ # we can display colors if we force mode to TRUE_COLOR
16
+ Paint.mode = 0xFFFFFF
17
+ end
18
+ rescue LoadError
19
+ raise "The 'paint' gem is required to use the rainbow outputter."
20
+ end
21
+ super
22
+ @line_color = 0
23
+ @color = 0
24
+ @state = :normal
25
+ end
26
+
27
+ # The algorithm is from lolcat (https://github.com/busyloop/lolcat)
28
+ # lolcat is released with WTFPL
29
+ def rainbow
30
+ red = Math.sin(0.3 * @color + 0) * 127 + 128
31
+ green = Math.sin(0.3 * @color + 2 * Math::PI / 3) * 127 + 128
32
+ blue = Math.sin(0.3 * @color + 4 * Math::PI / 3) * 127 + 128
33
+ @color += 1 / 8.0
34
+ format("%<red>02X%<green>02X%<blue>02X", red: red, green: green, blue: blue)
35
+ end
36
+
37
+ def colorize(color, string)
38
+ if @color && @stream.isatty
39
+ if %i[green rainbow].include?(color)
40
+ a = string.chars.map do |c|
41
+ case @state
42
+ when :normal
43
+ case c
44
+ when "\e"
45
+ @state = :ansi
46
+ when "\n"
47
+ @line_color += 1
48
+ @color = @line_color
49
+ c
50
+ else
51
+ Paint[c, rainbow]
52
+ end
53
+ when :ansi
54
+ @state = :normal if c == 'm'
55
+ end
56
+ end
57
+ a.join
58
+ else
59
+ "\033[#{COLORS[color]}m#{string}\033[0m"
60
+ end
61
+ else
62
+ string
63
+ end
64
+ end
65
+
66
+ def start_spin
67
+ return unless @spin && @stream.isatty && !@spinning
68
+ @spinning = true
69
+ @spin_thread = Thread.new do
70
+ loop do
71
+ sleep(0.1)
72
+ @stream.print(colorize(:rainbow, @pinwheel.rotate!.first + "\b"))
73
+ end
74
+ end
75
+ end
76
+
77
+ def print_summary(results, elapsed_time = nil)
78
+ ok_set = results.ok_set
79
+ unless ok_set.empty?
80
+ @stream.puts colorize(:rainbow, format('Successful on %<size>d target%<plural>s: %<names>s',
81
+ size: ok_set.size,
82
+ plural: ok_set.size == 1 ? '' : 's',
83
+ names: ok_set.targets.map(&:safe_name).join(',')))
84
+ end
85
+
86
+ error_set = results.error_set
87
+ unless error_set.empty?
88
+ @stream.puts colorize(:red,
89
+ format('Failed on %<size>d target%<plural>s: %<names>s',
90
+ size: error_set.size,
91
+ plural: error_set.size == 1 ? '' : 's',
92
+ names: error_set.targets.map(&:safe_name).join(',')))
93
+ end
94
+
95
+ total_msg = format('Ran on %<size>d target%<plural>s',
96
+ size: results.size,
97
+ plural: results.size == 1 ? '' : 's')
98
+ total_msg << " in #{duration_to_string(elapsed_time)}" unless elapsed_time.nil?
99
+ @stream.puts colorize(:rainbow, total_msg)
100
+ end
101
+
102
+ def print_guide(guide, _topic)
103
+ @stream.puts colorize(:rainbow, guide)
104
+ end
105
+
106
+ def print_topics(topics)
107
+ content = String.new("Available topics are:\n")
108
+ content += topics.join("\n")
109
+ content += "\n\nUse `bolt guide <topic>` to view a specific guide."
110
+ @stream.puts colorize(:rainbow, content)
111
+ end
112
+
113
+ def print_message(message)
114
+ @stream.puts colorize(:rainbow, Bolt::Util::Format.stringify(message))
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bolt
4
+ class Outputter
5
+ def self.for_format(format, color, verbose, trace, spin)
6
+ case format
7
+ when 'human'
8
+ Bolt::Outputter::Human.new(color, verbose, trace, spin)
9
+ when 'json'
10
+ Bolt::Outputter::JSON.new(color, verbose, trace, false)
11
+ when 'rainbow'
12
+ Bolt::Outputter::Rainbow.new(color, verbose, trace, spin)
13
+ when nil
14
+ raise "Cannot use outputter before parsing."
15
+ end
16
+ end
17
+
18
+ def initialize(color, verbose, trace, spin, stream = $stdout)
19
+ @color = color
20
+ @verbose = verbose
21
+ @trace = trace
22
+ @stream = stream
23
+ @spin = spin
24
+ end
25
+
26
+ def indent(indent, string)
27
+ indent = ' ' * indent
28
+ string.gsub(/^/, indent.to_s)
29
+ end
30
+
31
+ def print_message
32
+ raise NotImplementedError, "print_message() must be implemented by the outputter class"
33
+ end
34
+
35
+ def print_error
36
+ raise NotImplementedError, "print_error() must be implemented by the outputter class"
37
+ end
38
+
39
+ def start_spin; end
40
+
41
+ def stop_spin; end
42
+
43
+ def spin
44
+ start_spin
45
+ begin
46
+ yield
47
+ ensure
48
+ stop_spin
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ require_relative 'outputter/human'
55
+ require_relative 'outputter/json'
56
+ require_relative 'outputter/logger'
57
+ require_relative 'outputter/rainbow'
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bolt
4
+ class PAL
5
+ module Issues
6
+ # Create issue using Issues api
7
+ PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING =
8
+ Puppet::Pops::Issues.issue :PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, :action do
9
+ "Plan language function '#{action}' cannot be used from declarative manifest code or apply blocks"
10
+ end
11
+
12
+ # Inventory version 2
13
+ UNSUPPORTED_INVENTORY_VERSION =
14
+ Puppet::Pops::Issues.issue :UNSUPPORTED_INVENTORY_VERSION, :action do
15
+ "Plan language function '#{action}' cannot be used with Inventory v1"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../bolt/util/puppet_log_level'
4
+
5
+ Puppet::Util::Log.newdesttype :logging do
6
+ match "Logging::Logger"
7
+
8
+ # Bolt log levels don't match exactly with Puppet log levels, so we use
9
+ # an explicit mapping.
10
+ def initialize(logger)
11
+ @external_logger = logger
12
+ end
13
+
14
+ def handle(log)
15
+ @external_logger.send(Bolt::Util::PuppetLogLevel::MAPPING[log.level], log.to_s)
16
+ end
17
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../bolt/pal/yaml_plan'
4
+
5
+ module Bolt
6
+ class PAL
7
+ class YamlPlan
8
+ class Evaluator
9
+ def initialize(analytics = Bolt::Analytics::NoopClient.new)
10
+ @logger = Bolt::Logger.logger(self)
11
+ @analytics = analytics
12
+ @evaluator = Puppet::Pops::Parser::EvaluatingParser.new
13
+ end
14
+
15
+ # This is the method that Puppet calls to evaluate the plan. The name
16
+ # makes more sense for .pp plans.
17
+ #
18
+ def evaluate_block_with_bindings(closure_scope, args_hash, plan)
19
+ plan_result = closure_scope.with_local_scope(args_hash) do |scope|
20
+ plan.steps.each do |step|
21
+ step_result = step.evaluate(scope, self)
22
+
23
+ scope.setvar(step.body['name'], step_result) if step.body['name']
24
+ end
25
+
26
+ evaluate_code_blocks(scope, plan.return)
27
+ end
28
+
29
+ throw :return, Puppet::Pops::Evaluator::Return.new(plan_result, nil, nil)
30
+ end
31
+
32
+ # Recursively evaluate any EvaluableString instances in the object.
33
+ #
34
+ def evaluate_code_blocks(scope, value)
35
+ # XXX We should establish a local scope here probably
36
+ case value
37
+ when Array
38
+ value.map { |element| evaluate_code_blocks(scope, element) }
39
+ when Hash
40
+ value.each_with_object({}) do |(k, v), o|
41
+ key = k.is_a?(EvaluableString) ? k.value : k
42
+ o[key] = evaluate_code_blocks(scope, v)
43
+ end
44
+ when EvaluableString
45
+ begin
46
+ value.evaluate(scope, @evaluator)
47
+ rescue StandardError => e
48
+ raise format_evaluate_error(e, value)
49
+ end
50
+ else
51
+ value
52
+ end
53
+ end
54
+
55
+ # Occasionally the Closure will ask us to evaluate what it assumes are
56
+ # AST objects. Because we've sidestepped the AST, they aren't, so just
57
+ # return the values as already evaluated.
58
+ #
59
+ def evaluate(value, _scope)
60
+ value
61
+ end
62
+
63
+ def format_evaluate_error(error, value)
64
+ # The Puppet::PreformattedError includes the line number of the
65
+ # evaluable string that caused the error, while the value includes the
66
+ # line number of the YAML plan that the string began on. To get the
67
+ # actual line number of the error, add these two numbers together.
68
+ line = error.line + value.line
69
+
70
+ # If the evaluable string is not a scalar literal, correct for it
71
+ # being on the same line as the step key.
72
+ line -= 1 if value.is_a?(BareString)
73
+
74
+ Bolt::PlanFailure.new(
75
+ error.basic_message,
76
+ 'bolt/evaluation-error',
77
+ { file: value.file, line: line }
78
+ )
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../bolt/pal/yaml_plan'
4
+ require_relative '../../../bolt/pal/yaml_plan/evaluator'
5
+ require 'psych'
6
+
7
+ module Bolt
8
+ class PAL
9
+ class YamlPlan
10
+ class Loader
11
+ class PuppetVisitor < Psych::Visitors::NoAliasRuby
12
+ def initialize(scanner, class_loader, file)
13
+ super(scanner, class_loader)
14
+ @file = file
15
+ end
16
+
17
+ def self.create_visitor(source_ref)
18
+ class_loader = Psych::ClassLoader::Restricted.new([], [])
19
+ scanner = Psych::ScalarScanner.new(class_loader)
20
+ new(scanner, class_loader, source_ref)
21
+ end
22
+
23
+ def deserialize(node)
24
+ if node.quoted
25
+ case node.style
26
+ when Psych::Nodes::Scalar::SINGLE_QUOTED
27
+ # Single-quoted strings are treated literally
28
+ # @ss is a ScalarScanner, from the base ToRuby visitor class
29
+ node.value
30
+ when Psych::Nodes::Scalar::DOUBLE_QUOTED
31
+ DoubleQuotedString.new(node.value, @file, node.start_line + 1)
32
+ # | style string
33
+ when Psych::Nodes::Scalar::LITERAL
34
+ CodeLiteral.new(node.value, @file, node.start_line + 1)
35
+ # > style string
36
+ else
37
+ @ss.tokenize(node.value)
38
+ end
39
+ else
40
+ value = @ss.tokenize(node.value)
41
+ if value.is_a?(String)
42
+ BareString.new(value, @file, node.start_line + 1)
43
+ else
44
+ value
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def self.parse_plan(yaml_string, source_ref)
51
+ # This passes the filename as the second arg for compatibility with Psych used with ruby < 2.6
52
+ # This can be removed when we remove support for ruby 2.5
53
+ parse_tree = if Psych.method(:parse).parameters.rassoc(:filename) == %i[key filename]
54
+ Psych.parse(yaml_string, filename: source_ref)
55
+ else
56
+ Psych.parse(yaml_string, source_ref)
57
+ end
58
+ PuppetVisitor.create_visitor(source_ref).accept(parse_tree)
59
+ end
60
+
61
+ def self.from_string(name, yaml_string, source_ref)
62
+ result = parse_plan(yaml_string, source_ref)
63
+ unless result.is_a?(Hash)
64
+ type = result.class.name
65
+ raise ArgumentError, "The data loaded from #{source_ref} does not contain an object - its type is #{type}"
66
+ end
67
+
68
+ begin
69
+ YamlPlan.new(name, result).freeze
70
+ rescue Bolt::Error => e
71
+ raise Puppet::ParseError.new(e.message, source_ref)
72
+ end
73
+ end
74
+
75
+ def self.create(loader, typed_name, source_ref, yaml_string)
76
+ plan_definition = from_string(typed_name.name, yaml_string, source_ref)
77
+ created = create_function_class(plan_definition)
78
+ closure_scope = nil
79
+
80
+ created.new(closure_scope, loader.private_loader)
81
+ end
82
+
83
+ def self.create_function_class(plan_definition)
84
+ Puppet::Functions.create_function(plan_definition.name, Puppet::Functions::PuppetFunction) do
85
+ closure = Puppet::Pops::Evaluator::Closure::Named.new(plan_definition.name,
86
+ YamlPlan::Evaluator.new,
87
+ plan_definition)
88
+ init_dispatch(closure)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end