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,219 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../bolt/error'
4
+ require_relative '../bolt/logger'
5
+ require_relative '../bolt/module'
6
+ require_relative '../bolt/util'
7
+
8
+ module Bolt
9
+ module PlanCreator
10
+ def self.validate_plan_name(project, plan_name)
11
+ if project.name.nil?
12
+ raise Bolt::Error.new(
13
+ "Project directory '#{project.path}' is not a named project. Unable to create "\
14
+ "a project-level plan. To name a project, set the 'name' key in the 'bolt-project.yaml' "\
15
+ "configuration file.",
16
+ "bolt/unnamed-project-error"
17
+ )
18
+ end
19
+
20
+ if plan_name !~ Bolt::Module::CONTENT_NAME_REGEX
21
+ message = <<~MESSAGE.chomp
22
+ Invalid plan name '#{plan_name}'. Plan names are composed of one or more name segments
23
+ separated by double colons '::'.
24
+
25
+ Each name segment must begin with a lowercase letter, and can only include lowercase
26
+ letters, digits, and underscores.
27
+
28
+ Examples of valid plan names:
29
+ - #{project.name}
30
+ - #{project.name}::my_plan
31
+ MESSAGE
32
+
33
+ raise Bolt::ValidationError, message
34
+ end
35
+
36
+ prefix, _, basename = segment_plan_name(plan_name)
37
+
38
+ unless prefix == project.name
39
+ message = "Incomplete plan name: A plan name must be prefixed with the name of the "\
40
+ "project or module. Did you mean '#{project.name}::#{plan_name}'?"
41
+
42
+ raise Bolt::ValidationError, message
43
+ end
44
+
45
+ %w[pp yaml].each do |ext|
46
+ next unless (path = project.plans_path + "#{basename}.#{ext}").exist?
47
+ raise Bolt::Error.new(
48
+ "A plan with the name '#{plan_name}' already exists at '#{path}', nothing to do.",
49
+ 'bolt/existing-plan-error'
50
+ )
51
+ end
52
+ end
53
+
54
+ # Create a new plan from the plan templates based on which language the
55
+ # user configured, and whether the plan wraps a script.
56
+ #
57
+ # @param plans_path [string] The path to the new plan
58
+ # @param plan_name [string] The name of the new plan
59
+ # @param is_puppet [boolean] Whether to create a Puppet language plan
60
+ # @param script [string] A reference to a script for the new plan to run
61
+ #
62
+ def self.create_plan(plans_path, plan_name, is_puppet: false, script: nil)
63
+ _, name_segments, basename = segment_plan_name(plan_name)
64
+ dir_path = plans_path.join(*name_segments)
65
+
66
+ begin
67
+ FileUtils.mkdir_p(dir_path)
68
+ rescue Errno::EEXIST => e
69
+ raise Bolt::Error.new(
70
+ "#{e.message}; unable to create plan directory '#{dir_path}'",
71
+ 'bolt/existing-file-error'
72
+ )
73
+ end
74
+
75
+ type = is_puppet ? 'pp' : 'yaml'
76
+ plan_path = dir_path + "#{basename}.#{type}"
77
+ plan_template = if is_puppet && script
78
+ puppet_script_plan(plan_name, script)
79
+ elsif is_puppet
80
+ puppet_plan(plan_name)
81
+ elsif script
82
+ yaml_script_plan(script)
83
+ else
84
+ yaml_plan(plan_name)
85
+ end
86
+ begin
87
+ File.write(plan_path, plan_template)
88
+ rescue Errno::EACCES => e
89
+ raise Bolt::FileError.new(
90
+ "#{e.message}; unable to create plan",
91
+ plan_path
92
+ )
93
+ end
94
+
95
+ { name: plan_name, path: plan_path }
96
+ end
97
+
98
+ def self.segment_plan_name(plan_name)
99
+ prefix, *name_segments, basename = plan_name.split('::')
100
+
101
+ # If the plan name is just the project name, then create an 'init' plan.
102
+ # Otherwise, use the last name segment for the plan's filename.
103
+ basename ||= 'init'
104
+
105
+ [prefix, name_segments, basename]
106
+ end
107
+
108
+ # Template for a new simple YAML plan.
109
+ #
110
+ # @param plan_name [string] The name of the new plan
111
+ #
112
+ private_class_method def self.yaml_plan(plan_name)
113
+ <<~YAML
114
+ # This is the structure of a simple plan. To learn more about writing
115
+ # YAML plans, see the documentation: http://pup.pt/bolt-yaml-plans
116
+
117
+ # The description sets the description of the plan that will appear
118
+ # in 'bolt plan show' output.
119
+ description: A plan created with bolt plan new
120
+
121
+ # The parameters key defines the parameters that can be passed to
122
+ # the plan.
123
+ parameters:
124
+ targets:
125
+ type: TargetSpec
126
+ description: A list of targets to run actions on
127
+ default: localhost
128
+
129
+ # The steps key defines the actions the plan will take in order.
130
+ steps:
131
+ - message: Hello from #{plan_name}
132
+ - name: command_step
133
+ command: whoami
134
+ targets: $targets
135
+
136
+ # The return key sets the return value of the plan.
137
+ return: $command_step
138
+ YAML
139
+ end
140
+
141
+ # Template for a new YAML plan that runs a script.
142
+ #
143
+ # @param script [string] A reference to the script to run.
144
+ #
145
+ private_class_method def self.yaml_script_plan(script)
146
+ <<~YAML
147
+ # This is the structure of a simple plan. To learn more about writing
148
+ # YAML plans, see the documentation: http://pup.pt/bolt-yaml-plans
149
+
150
+ # The description sets the description of the plan that will appear
151
+ # in 'bolt plan show' output.
152
+ description: A plan created with bolt plan new
153
+
154
+ # The parameters key defines the parameters that can be passed to
155
+ # the plan.
156
+ parameters:
157
+ targets:
158
+ type: TargetSpec
159
+ description: A list of targets to run actions on
160
+
161
+ # The steps key defines the actions the plan will take in order.
162
+ steps:
163
+ - name: run_script
164
+ script: #{script}
165
+ targets: $targets
166
+
167
+ # The return key sets the return value of the plan.
168
+ return: $run_script
169
+ YAML
170
+ end
171
+
172
+ # Template for a new simple Puppet plan.
173
+ #
174
+ # @param plan_name [string] The name of the new plan
175
+ #
176
+ private_class_method def self.puppet_plan(plan_name)
177
+ <<~PUPPET
178
+ # This is the structure of a simple plan. To learn more about writing
179
+ # Puppet plans, see the documentation: http://pup.pt/bolt-puppet-plans
180
+
181
+ # The summary sets the description of the plan that will appear
182
+ # in 'bolt plan show' output. Bolt uses puppet-strings to parse the
183
+ # summary and parameters from the plan.
184
+ # @summary A plan created with bolt plan new.
185
+ # @param targets The targets to run on.
186
+ plan #{plan_name} (
187
+ TargetSpec $targets = "localhost"
188
+ ) {
189
+ out::message("Hello from #{plan_name}")
190
+ $command_result = run_command('whoami', $targets)
191
+ return $command_result
192
+ }
193
+ PUPPET
194
+ end
195
+
196
+ # Template for a new Puppet plan that only runs a script.
197
+ #
198
+ # @param plan_name [string] The name of the new plan
199
+ # @param script [string] A reference to the script to run
200
+ #
201
+ private_class_method def self.puppet_script_plan(plan_name, script)
202
+ <<~PUPPET
203
+ # This is the structure of a simple plan. To learn more about writing
204
+ # Puppet plans, see the documentation: http://pup.pt/bolt-puppet-plans
205
+
206
+ # The summary sets the description of the plan that will appear
207
+ # in 'bolt plan show' output. Bolt uses puppet-strings to parse the
208
+ # summary and parameters from the plan.
209
+ # @summary A plan created with bolt plan new.
210
+ # @param targets The targets to run on.
211
+ plan #{plan_name} (
212
+ TargetSpec $targets
213
+ ) {
214
+ return run_script('#{script}', $targets)
215
+ }
216
+ PUPPET
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fiber'
4
+
5
+ module Bolt
6
+ class PlanFuture
7
+ attr_reader :fiber, :id, :scope
8
+ attr_accessor :value, :plan_stack
9
+
10
+ def initialize(fiber, id, plan_id:, name: nil, scope: nil)
11
+ @fiber = fiber
12
+ @id = id
13
+ @name = name
14
+ @value = nil
15
+
16
+ # Default to Puppet's current global_scope, otherwise things will
17
+ # blow up when the Fiber Executor tries to override the global_scope.
18
+ @scope = scope || Puppet.lookup(:global_scope) { nil }
19
+
20
+ # The plan invocation ID when the Future is created may be
21
+ # different from the plan ID of the Future when we switch to it if a new
22
+ # plan was run inside the Future, so keep track of the plans that a
23
+ # Future is executing in as a stack. When one plan finishes, pop it off
24
+ # since now we're in the calling plan. These IDs are unique to each plan
25
+ # invocation, not just plan names.
26
+ @plan_stack = [plan_id]
27
+ end
28
+
29
+ def original_plan
30
+ @plan_stack.last
31
+ end
32
+
33
+ def current_plan
34
+ @plan_stack.first
35
+ end
36
+
37
+ def name
38
+ @name || @id
39
+ end
40
+
41
+ def to_s
42
+ "Future '#{name}'"
43
+ end
44
+
45
+ def alive?
46
+ fiber.alive?
47
+ end
48
+
49
+ def raise(exception)
50
+ # Make sure the value gets set
51
+ @value = exception
52
+ # This was introduced in Ruby 2.7
53
+ begin
54
+ # Raise an exception to kill the Fiber. If the Fiber has not been
55
+ # resumed yet, or is already terminated this will raise a FiberError.
56
+ # We don't especially care about the FiberError, as long as the Fiber
57
+ # doesn't report itself as alive.
58
+ fiber.raise(exception)
59
+ rescue FiberError
60
+ # If the Fiber is still alive, resume it with a block to raise the
61
+ # exception which will terminate it.
62
+ if fiber.alive?
63
+ fiber.resume { raise(exception) }
64
+ end
65
+ end
66
+ end
67
+
68
+ def resume
69
+ if fiber.alive?
70
+ @value = fiber.resume
71
+ else
72
+ @value
73
+ end
74
+ end
75
+
76
+ def state
77
+ if fiber.alive?
78
+ "running"
79
+ elsif value.is_a?(Exception)
80
+ "error"
81
+ else
82
+ "done"
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative '../bolt/error'
5
+ require_relative '../bolt/util'
6
+
7
+ module Bolt
8
+ class PlanResult
9
+ attr_accessor :status, :value
10
+
11
+ # This must be called from inside a compiler
12
+ def self.from_pcore(result, status)
13
+ result = Bolt::Util.walk_vals(result) do |v|
14
+ if v.is_a?(Puppet::DataTypes::Error)
15
+ Bolt::PuppetError.from_error(v)
16
+ else
17
+ v
18
+ end
19
+ end
20
+ new(result, status)
21
+ end
22
+
23
+ def initialize(value, status)
24
+ @value = value
25
+ @status = status
26
+ end
27
+
28
+ def ok?
29
+ @status == 'success'
30
+ end
31
+
32
+ def ==(other)
33
+ value == other.value && status == other.status
34
+ end
35
+
36
+ def to_json(*args)
37
+ @value.to_json(*args)
38
+ end
39
+
40
+ def to_s
41
+ to_json
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require_relative '../../bolt/error'
5
+ require_relative '../../bolt/util'
6
+
7
+ module Bolt
8
+ class Plugin
9
+ class Cache
10
+ attr_reader :reference, :plugin_cache_file, :default_config, :id
11
+
12
+ def initialize(reference, plugin_cache_file, default_config)
13
+ @reference = reference
14
+ @plugin_cache_file = plugin_cache_file
15
+ @default_config = default_config
16
+ end
17
+
18
+ def read_and_clean_cache
19
+ return if ttl == 0
20
+ validate
21
+
22
+ # Luckily we don't need to use a serious hash algorithm
23
+ require 'digest/bubblebabble'
24
+ r = reference.reject { |k, _| k == '_cache' }.sort.to_s
25
+ @id = Digest::SHA2.bubblebabble(r)[0..20]
26
+
27
+ unmodified = true
28
+ # First remove any cache entries past their ttl
29
+ # This prevents removing plugins from leaving orphaned cache entries
30
+ cache.delete_if do |_, entry|
31
+ expired = Time.now - Time.parse(entry['mtime']) >= entry['ttl']
32
+ unmodified = false if expired
33
+ expired
34
+ end
35
+ File.write(plugin_cache_file, cache.to_json) unless cache.empty? || unmodified
36
+
37
+ cache.dig(id, 'result')
38
+ end
39
+
40
+ private def cache
41
+ @cache ||= Bolt::Util.read_optional_json_file(@plugin_cache_file, 'cache')
42
+ end
43
+
44
+ def write_cache(result)
45
+ cache.merge!({ id => { 'result' => result,
46
+ 'mtime' => Time.now,
47
+ 'ttl' => ttl } })
48
+ FileUtils.touch(plugin_cache_file)
49
+ File.write(plugin_cache_file, cache.to_json)
50
+ end
51
+
52
+ def validate
53
+ # The default cache `plugin-cache` will be validated by the config
54
+ # validator
55
+ return if reference['_cache'].nil?
56
+ r = reference['_cache']
57
+ unless r.is_a?(Hash)
58
+ raise Bolt::ValidationError,
59
+ "_cache must be a Hash, received #{r.class}: #{r.inspect}"
60
+ end
61
+
62
+ unless r.key?('ttl')
63
+ raise Bolt::ValidationError, "_cache must set 'ttl' key."
64
+ end
65
+
66
+ unless r['ttl'] >= 0
67
+ raise Bolt::ValidationError, "'ttl' key under '_cache' must be a minimum of 0."
68
+ end
69
+ end
70
+
71
+ private def ttl
72
+ @ttl ||= reference.dig('_cache', 'ttl') || default_config['ttl']
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ module Bolt
5
+ class Plugin
6
+ class EnvVar
7
+ class InvalidPluginData < Bolt::Plugin::PluginError
8
+ def initialize(msg, plugin)
9
+ msg = "Invalid Plugin Data for #{plugin}: #{msg}"
10
+ super(msg, 'bolt/invalid-plugin-data')
11
+ end
12
+ end
13
+
14
+ def initialize(*_args); end
15
+
16
+ def name
17
+ 'env_var'
18
+ end
19
+
20
+ def hooks
21
+ hook_descriptions.keys
22
+ end
23
+
24
+ def hook_descriptions
25
+ {
26
+ resolve_reference: 'Read values stored in environment variables.',
27
+ validate_resolve_reference: nil
28
+ }
29
+ end
30
+
31
+ def validate_resolve_reference(opts)
32
+ unless opts['var']
33
+ raise Bolt::ValidationError, "env_var plugin requires that the 'var' is specified"
34
+ end
35
+ return if opts['optional'] || opts['default']
36
+ unless ENV[opts['var']]
37
+ raise Bolt::ValidationError, "env_var plugin requires that the var '#{opts['var']}' be set"
38
+ end
39
+ end
40
+
41
+ def resolve_reference(opts)
42
+ reference = ENV[opts['var']]
43
+ if opts['json'] && reference
44
+ begin
45
+ reference = JSON.parse(reference)
46
+ rescue JSON::ParserError => e
47
+ raise InvalidPluginData.new(e.message, name)
48
+ end
49
+ end
50
+ reference || opts['default']
51
+ end
52
+ end
53
+ end
54
+ end