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,247 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative '../bolt/error'
5
+
6
+ module Bolt
7
+ class Result
8
+ attr_reader :target, :value, :action, :object
9
+
10
+ def self.from_exception(target, exception, action: 'action', position: [])
11
+ details = create_details(position)
12
+ if exception.is_a?(Bolt::Error)
13
+ error = Bolt::Util.deep_merge({ 'details' => details }, exception.to_h)
14
+ else
15
+ details['class'] = exception.class.to_s
16
+ error = {
17
+ 'kind' => 'puppetlabs.tasks/exception-error',
18
+ 'issue_code' => 'EXCEPTION',
19
+ 'msg' => exception.message,
20
+ 'details' => details
21
+ }
22
+ error['details']['stack_trace'] = exception.backtrace.join('\n') if exception.backtrace
23
+ end
24
+ Result.new(target, error: error, action: action)
25
+ end
26
+
27
+ def self.create_details(position)
28
+ %w[file line].zip(position).to_h.compact
29
+ end
30
+
31
+ def self.for_lookup(target, key, value)
32
+ val = { 'value' => value }
33
+ new(target, value: val, action: 'lookup', object: key)
34
+ end
35
+
36
+ def self.for_command(target, value, action, command, position)
37
+ details = create_details(position)
38
+ unless value['exit_code'] == 0
39
+ details['exit_code'] = value['exit_code']
40
+ value['_error'] = {
41
+ 'kind' => 'puppetlabs.tasks/command-error',
42
+ 'issue_code' => 'COMMAND_ERROR',
43
+ 'msg' => "The command failed with exit code #{value['exit_code']}",
44
+ 'details' => details
45
+ }
46
+ end
47
+ new(target, value: value, action: action, object: command)
48
+ end
49
+
50
+ def self.for_task(target, stdout, stderr, exit_code, task, position)
51
+ stdout.force_encoding('utf-8') unless stdout.encoding == Encoding::UTF_8
52
+
53
+ details = create_details(position)
54
+ value = if stdout.valid_encoding?
55
+ parse_hash(stdout) || { '_output' => stdout }
56
+ else
57
+ { '_error' => { 'kind' => 'puppetlabs.tasks/task-error',
58
+ 'issue_code' => 'TASK_ERROR',
59
+ 'msg' => 'The task result contained invalid UTF-8 on stdout',
60
+ 'details' => details } }
61
+ end
62
+
63
+ if exit_code != 0 && value['_error'].nil?
64
+ msg = if stdout.empty?
65
+ if stderr.empty?
66
+ "The task failed with exit code #{exit_code} and no output"
67
+ else
68
+ "The task failed with exit code #{exit_code} and no stdout, but stderr contained:\n#{stderr}"
69
+ end
70
+ else
71
+ "The task failed with exit code #{exit_code}"
72
+ end
73
+ details['exit_code'] = exit_code
74
+ value['_error'] = { 'kind' => 'puppetlabs.tasks/task-error',
75
+ 'issue_code' => 'TASK_ERROR',
76
+ 'msg' => msg,
77
+ 'details' => details }
78
+ end
79
+
80
+ if value.key?('_error')
81
+ unless value['_error'].is_a?(Hash) && value['_error'].key?('msg')
82
+ details['original_error'] = value['_error']
83
+ value['_error'] = {
84
+ 'msg' => "Invalid error returned from task #{task}: #{value['_error'].inspect}. Error "\
85
+ "must be an object with a msg key.",
86
+ 'kind' => 'bolt/invalid-task-error',
87
+ 'details' => details
88
+ }
89
+ end
90
+
91
+ value['_error']['kind'] ||= 'bolt/error'
92
+ value['_error']['details'] ||= details
93
+ end
94
+
95
+ if value.key?('_sensitive')
96
+ value['_sensitive'] = Puppet::Pops::Types::PSensitiveType::Sensitive.new(value['_sensitive'])
97
+ end
98
+
99
+ new(target, value: value, action: 'task', object: task)
100
+ end
101
+
102
+ def self.parse_hash(string)
103
+ value = JSON.parse(string)
104
+ value if value.is_a? Hash
105
+ rescue JSON::ParserError
106
+ nil
107
+ end
108
+
109
+ def self.for_upload(target, source, destination)
110
+ new(target, message: "Uploaded '#{source}' to '#{target.host}:#{destination}'", action: 'upload', object: source)
111
+ end
112
+
113
+ def self.for_download(target, source, destination, download)
114
+ msg = "Downloaded '#{target.host}:#{source}' to '#{destination}'"
115
+ value = { 'path' => download }
116
+
117
+ new(target, value: value, message: msg, action: 'download', object: source)
118
+ end
119
+
120
+ # Satisfies the Puppet datatypes API
121
+ def self.from_asserted_args(target, value)
122
+ new(target, value: value)
123
+ end
124
+
125
+ def self._pcore_init_from_hash
126
+ raise "Result shouldn't be instantiated from a pcore_init class method. How did this get called?"
127
+ end
128
+
129
+ def _pcore_init_from_hash(init_hash)
130
+ opts = init_hash.reject { |k, _v| k == 'target' }
131
+ initialize(init_hash['target'], **opts.transform_keys(&:to_sym))
132
+ end
133
+
134
+ def _pcore_init_hash
135
+ { 'target' => @target,
136
+ 'error' => @value['_error'],
137
+ 'message' => @value['_output'],
138
+ 'value' => @value,
139
+ 'action' => @action,
140
+ 'object' => @object }
141
+ end
142
+
143
+ def initialize(target, error: nil, message: nil, value: nil, action: 'action', object: nil)
144
+ @target = target
145
+ @value = value || {}
146
+ @action = action
147
+ @object = object
148
+ if error && !error.is_a?(Hash)
149
+ raise "TODO: how did we get a string error"
150
+ end
151
+ @value['_error'] = error if error
152
+ @value['_output'] = message if message
153
+ end
154
+
155
+ def message
156
+ @value['_output']
157
+ end
158
+
159
+ def message?
160
+ message && !message.strip.empty?
161
+ end
162
+
163
+ def generic_value
164
+ safe_value.reject { |k, _| %w[_error _output].include? k }
165
+ end
166
+
167
+ def eql?(other)
168
+ self.class == other.class &&
169
+ target == other.target &&
170
+ value == other.value
171
+ end
172
+ alias == eql?
173
+
174
+ def [](key)
175
+ value[key]
176
+ end
177
+
178
+ def to_json(opts = nil)
179
+ to_data.to_json(opts)
180
+ end
181
+
182
+ def to_s
183
+ to_json
184
+ end
185
+
186
+ # This is the value with all non-UTF-8 characters removed, suitable for
187
+ # printing or converting to JSON. It *should* only be possible to have
188
+ # non-UTF-8 characters in stdout/stderr keys as they are not allowed from
189
+ # tasks but we scrub the whole thing just in case.
190
+ def safe_value
191
+ Bolt::Util.walk_vals(value) do |val|
192
+ if val.is_a?(String)
193
+ # Replace invalid bytes with hex codes, ie. \xDE\xAD\xBE\xEF
194
+ val.scrub { |c| c.bytes.map { |b| "\\x" + b.to_s(16).upcase }.join }
195
+ else
196
+ val
197
+ end
198
+ end
199
+ end
200
+
201
+ def to_data
202
+ serialized_value = safe_value
203
+
204
+ if serialized_value.key?('_sensitive') &&
205
+ serialized_value['_sensitive'].is_a?(Puppet::Pops::Types::PSensitiveType::Sensitive)
206
+ serialized_value['_sensitive'] = serialized_value['_sensitive'].to_s
207
+ end
208
+
209
+ {
210
+ "target" => @target.name,
211
+ "action" => action,
212
+ "object" => object,
213
+ "status" => status,
214
+ "value" => serialized_value
215
+ }
216
+ end
217
+
218
+ def status
219
+ ok? ? 'success' : 'failure'
220
+ end
221
+
222
+ def ok?
223
+ error_hash.nil?
224
+ end
225
+ alias ok ok?
226
+ alias success? ok?
227
+
228
+ # This allows access to errors outside puppet compilation
229
+ # it should be prefered over error in bolt code
230
+ def error_hash
231
+ value['_error']
232
+ end
233
+
234
+ # Warning: This will fail outside of a compilation.
235
+ # Use error_hash inside bolt.
236
+ # Is it crazy for this to behave differently outside a compiler?
237
+ def error
238
+ if error_hash
239
+ Puppet::DataTypes::Error.from_asserted_hash(error_hash)
240
+ end
241
+ end
242
+
243
+ def sensitive
244
+ value['_sensitive']
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bolt
4
+ class ResultSet
5
+ attr_accessor :elapsed_time
6
+ attr_reader :results
7
+
8
+ include Enumerable
9
+
10
+ # We only want want to include these when puppet is loaded
11
+ def self.include_iterable
12
+ include(Puppet::Pops::Types::Iterable)
13
+ include(Puppet::Pops::Types::IteratorProducer)
14
+ end
15
+
16
+ def self._pcore_init_from_hash
17
+ raise "ResultSet shouldn't be instantiated from a pcore_init class method. How did this get called?"
18
+ end
19
+
20
+ def _pcore_init_from_hash(init_hash)
21
+ initialize(init_hash['results'])
22
+ end
23
+
24
+ def _pcore_init_hash
25
+ { 'results' => @results }
26
+ end
27
+
28
+ def iterator
29
+ if Object.const_defined?(:Puppet) && Puppet.const_defined?(:Pops) &&
30
+ self.class.included_modules.include?(Puppet::Pops::Types::Iterable)
31
+ Puppet::Pops::Types::Iterable.on(@results, Bolt::Result)
32
+ else
33
+ raise NotImplementedError, "iterator requires puppet code to be loaded."
34
+ end
35
+ end
36
+
37
+ def initialize(results)
38
+ @results = results
39
+ end
40
+
41
+ def each
42
+ @results.each { |r| yield r }
43
+ self
44
+ end
45
+
46
+ def filter_set
47
+ filtered = @results.select { |r| yield r }
48
+ self.class.new(filtered)
49
+ end
50
+
51
+ def result_hash
52
+ @result_hash ||= @results.each_with_object({}) do |result, acc|
53
+ acc[result.target.name] = result
54
+ end
55
+ end
56
+
57
+ def count
58
+ @results.size
59
+ end
60
+ alias length count
61
+ alias size count
62
+
63
+ def empty
64
+ @results.empty?
65
+ end
66
+ alias empty? empty
67
+
68
+ def targets
69
+ results.map(&:target)
70
+ end
71
+
72
+ def names
73
+ @results.map { |r| r.target.name }
74
+ end
75
+
76
+ def ok
77
+ @results.all?(&:ok?)
78
+ end
79
+ alias ok? ok
80
+
81
+ def error_set
82
+ filtered = @results.reject(&:ok?)
83
+ ResultSet.new(filtered)
84
+ end
85
+
86
+ def ok_set
87
+ filtered = @results.select(&:success?)
88
+ self.class.new(filtered)
89
+ end
90
+
91
+ def find(target_name)
92
+ result_hash[target_name]
93
+ end
94
+
95
+ def first
96
+ @results.first
97
+ end
98
+
99
+ def eql?(other)
100
+ self.class == other.class && @results == other.results
101
+ end
102
+
103
+ def to_json(opts = nil)
104
+ to_data.to_json(opts)
105
+ end
106
+
107
+ def to_data
108
+ @results.map(&:to_data)
109
+ end
110
+ alias to_a to_data
111
+
112
+ def to_s
113
+ to_json
114
+ end
115
+
116
+ def ==(other)
117
+ eql?(other)
118
+ end
119
+
120
+ def [](from, up_to = nil)
121
+ if up_to
122
+ @results[from..up_to]
123
+ else
124
+ @results[from]
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bolt
4
+ class Shell
5
+ class Bash < Shell
6
+ class Tmpdir
7
+ def initialize(shell, path)
8
+ @shell = shell
9
+ @owner = shell.conn.user
10
+ @path = path
11
+ @logger = shell.logger
12
+ end
13
+
14
+ def to_s
15
+ @path
16
+ end
17
+
18
+ def mkdirs(subdirs)
19
+ abs_subdirs = subdirs.map { |subdir| File.join(@path, subdir) }
20
+ result = @shell.execute(['mkdir', '-p'] + abs_subdirs)
21
+ if result.exit_code != 0
22
+ message = "Could not create subdirectories in '#{@path}': #{result.stderr.string}"
23
+ raise Bolt::Node::FileError.new(message, 'MKDIR_ERROR')
24
+ end
25
+ end
26
+
27
+ def chown(owner, force: false)
28
+ return if owner.nil? || (owner == @owner && !force)
29
+
30
+ result = @shell.execute(['id', '-g', owner])
31
+ if result.exit_code != 0
32
+ message = "Could not identify group of user #{owner}: #{result.stderr.string}"
33
+ raise Bolt::Node::FileError.new(message, 'ID_ERROR')
34
+ end
35
+ group = result.stdout.string.chomp
36
+
37
+ # Chown can only be run by root.
38
+ result = @shell.execute(['chown', '-R', "#{owner}:#{group}", @path], sudoable: true, run_as: 'root')
39
+ if result.exit_code != 0
40
+ message = "Could not change owner of '#{@path}' to #{owner}: #{result.stderr.string}"
41
+ raise Bolt::Node::FileError.new(message, 'CHOWN_ERROR')
42
+ end
43
+
44
+ # File ownership successfully changed, record the new owner.
45
+ @owner = owner
46
+ end
47
+
48
+ def delete
49
+ result = @shell.execute(['rm', '-rf', @path], sudoable: true, run_as: @owner)
50
+ if result.exit_code != 0
51
+ Bolt::Logger.warn(
52
+ "fail_cleanup",
53
+ "Failed to clean up tmpdir '#{@path}': #{result.stderr.string}"
54
+ )
55
+ end
56
+ # For testing
57
+ result.stderr.string
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end