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,18 @@
1
+ ---
2
+ topic: module
3
+ guide: |
4
+ Modules are shareable, reusable packages of Puppet content. They can include
5
+ tasks, plans, functions, and other types of content that you can use in your
6
+ project. You can download and install modules to your project from the
7
+ Puppet Forge or write your own modules. Bolt also ships with several helpful
8
+ modules pre-installed that are available to all of your projects.
9
+
10
+ Bolt makes it easy to manage the modules that your project depends on. You
11
+ can use Bolt commands to install a project's modules, add new modules to a
12
+ project, and view the modules that are available to the project.
13
+
14
+ To learn more about managing modules in a project, see the documentation.
15
+ To learn how modules are loaded by Bolt, see the 'modulepath' guide.
16
+
17
+ documentation:
18
+ - https://pup.pt/bolt-modules
@@ -0,0 +1,24 @@
1
+ ---
2
+ topic: modulepath
3
+ guide: |
4
+ The modulepath is an ordered list of directories that Bolt loads modules
5
+ from. When Bolt runs a command, it automatically loads modules from the
6
+ modulepath.
7
+
8
+ While Bolt has a default modulepath, you can also configure your own
9
+ modulepath, which can include directories within the project or directories
10
+ elsewhere on your system. Regardless of whether your project uses a default
11
+ or configured modulepath, Bolt automatically adds directories to the
12
+ modulepath. This includes modules containing core Bolt content, which is
13
+ added to the beginning of the modulepath, and bundled content, which is
14
+ added to the end of the modulepath.
15
+
16
+ Modules loaded from a directory listed earlier in the modulepath take
17
+ precedence over modules with the same name loaded from a directory later in
18
+ the modulepath. Bolt will not warn or error when two modules share a name
19
+ and instead will ignore modules with a lower precedence.
20
+
21
+ To learn more about modules, see the 'module' guide.
22
+
23
+ documentation:
24
+ - https://pup.pt/bolt-project-reference#modulepath
@@ -0,0 +1,21 @@
1
+ ---
2
+ topic: project
3
+ guide: |
4
+ A Bolt project is a directory that serves as the launching point for Bolt
5
+ and allows you to create a shareable orchestration application. Projects
6
+ typically include a project configuration file, an inventory file, and any
7
+ content you use in your project workflow, such as tasks and plans.
8
+
9
+ When you run Bolt, it runs in the context of a project. If the directory you
10
+ run Bolt from is not a project, Bolt attempts to find a project by
11
+ traversing the parent directories. If Bolt is unable to find a project, it
12
+ runs from the default project, located at '~/.puppetlabs/bolt'.
13
+
14
+ A directory is only considered a Bolt project when it has a project
15
+ configuration file named 'bolt-project.yaml'. Bolt doesn't load project data
16
+ and content, including inventory files, unless the data and content are part
17
+ of a project.
18
+
19
+ documentation:
20
+ - https://pup.pt/bolt-projects
21
+ - https://pup.pt/bolt-project-reference
@@ -0,0 +1,28 @@
1
+ ---
2
+ topic: targets
3
+ guide: |
4
+ A target is a device that Bolt connects to and runs actions on. Targets can
5
+ be physical, such as servers, or virtual, such as containers or virtual
6
+ machines.
7
+
8
+ Several of Bolt's commands connect to targets and run actions on them.
9
+ These commands require a target or targets to run on. You can specify
10
+ targets to a command using one of the following command-line options:
11
+
12
+ *nix options Powershell options
13
+ -t, --targets TARGETS -T, -Targets TARGETS
14
+ -q, --query QUERY -Q, -Query QUERY
15
+ --rerun FILTER -Rerun FILTER
16
+
17
+ The 'targets' option accepts a comma-separated list of target URIs or group
18
+ names, or can read a target list from an input file '@<file>' or stdin '-'.
19
+ URIs can be specified with the format [protocol://][user@]host[:port]. To
20
+ learn more about available protocols and their defaults, run 'bolt guide
21
+ transports'.
22
+
23
+ Typically, targets and their configuration and data are listed in a
24
+ project's inventory file. For more information about inventory files,
25
+ see 'bolt guide inventory'.
26
+
27
+ documentation:
28
+ - https://pup.pt/bolt-commands
@@ -0,0 +1,22 @@
1
+ ---
2
+ topic: transports
3
+ guide: |
4
+ Bolt uses transports (also known as protocols) to establish a connection
5
+ with a target in order to run actions on the target. The default transport is
6
+ SSH, and you can see available transports along with their configuration
7
+ options and defaults at http://pup.pt/bolt-reference.
8
+
9
+ You can specify a transport for a target by prepending '<transport>://' to
10
+ the target's URI. For example, to connect to a target with hostname
11
+ 'example.com' as user 'Administrator' using the WinRM transport, you would
12
+ pass the following to the target flag:
13
+ winrm://Administrator@example.com
14
+
15
+ You can also specify a default transport for all targets by passing the
16
+ '--transport' flag on *nix systems and the '-Transport' flag in Powershell.
17
+ Finally, you can set the transport for a target in the inventory. For more
18
+ information about the Bolt inventory, run 'bolt guide inventory'.
19
+
20
+ documentation:
21
+ - https://pup.pt/bolt-commands#specify-a-transport
22
+ - http://pup.pt/bolt-inventory#transport-configuration
@@ -0,0 +1,233 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../bolt/util'
4
+ require_relative '../bolt/version'
5
+ require 'find'
6
+ require 'json'
7
+ require 'logging'
8
+ require 'securerandom'
9
+
10
+ module Bolt
11
+ module Analytics
12
+ PROTOCOL_VERSION = 1
13
+ APPLICATION_NAME = 'bolt'
14
+ TRACKING_ID = 'UA-120367942-1'
15
+ TRACKING_URL = 'https://google-analytics.com/collect'
16
+ CUSTOM_DIMENSIONS = {
17
+ operating_system: :cd1,
18
+ inventory_nodes: :cd2,
19
+ inventory_groups: :cd3,
20
+ target_nodes: :cd4,
21
+ output_format: :cd5,
22
+ statement_count: :cd6,
23
+ resource_mean: :cd7,
24
+ plan_steps: :cd8,
25
+ return_type: :cd9,
26
+ inventory_version: :cd10,
27
+ boltdir_type: :cd11,
28
+ puppet_plan_count: :cd12,
29
+ yaml_plan_count: :cd13
30
+ }.freeze
31
+
32
+ def self.build_client(enabled = true)
33
+ begin
34
+ config_file = config_path
35
+ config = enabled ? load_config(config_file) : {}
36
+ rescue ArgumentError
37
+ config = { 'disabled' => true }
38
+ end
39
+
40
+ if !enabled || config['disabled'] || ENV['BOLT_DISABLE_ANALYTICS']
41
+ Bolt::Logger.debug "Analytics opt-out is set, analytics will be disabled"
42
+ NoopClient.new
43
+ else
44
+ unless config.key?('user-id')
45
+ config['user-id'] = SecureRandom.uuid
46
+ write_config(config_file, config)
47
+ end
48
+
49
+ Client.new(config['user-id'])
50
+ end
51
+ rescue StandardError => e
52
+ Bolt::Logger.debug "Failed to initialize analytics client, analytics will be disabled: #{e}"
53
+ NoopClient.new
54
+ end
55
+
56
+ def self.config_path
57
+ path = File.expand_path(File.join('~', '.puppetlabs', 'etc', 'bolt', 'analytics.yaml'))
58
+ old_path = File.expand_path(File.join('~', '.puppetlabs', 'bolt', 'analytics.yaml'))
59
+
60
+ if File.exist?(path)
61
+ if File.exist?(old_path)
62
+ message = "Detected analytics configuration files at '#{old_path}' and '#{path}'. Loading "\
63
+ "analytics configuration from '#{path}'."
64
+ Bolt::Logger.warn_once('duplicate_analytics', message)
65
+ end
66
+
67
+ path
68
+ elsif File.exist?(old_path)
69
+ old_path
70
+ else
71
+ path
72
+ end
73
+ end
74
+
75
+ def self.load_config(filename)
76
+ if File.exist?(filename)
77
+ Bolt::Util.read_optional_yaml_hash(filename, 'analytics')
78
+ else
79
+ unless ENV['BOLT_DISABLE_ANALYTICS']
80
+ msg = <<~ANALYTICS
81
+ Bolt collects data about how you use it. You can opt out of providing this data.
82
+ To learn how to disable data collection, or see what data Bolt collects and why,
83
+ see http://pup.pt/bolt-analytics
84
+ ANALYTICS
85
+ Bolt::Logger.warn_once('analytics_opt_out', msg)
86
+ end
87
+
88
+ {}
89
+ end
90
+ end
91
+
92
+ def self.write_config(filename, config)
93
+ FileUtils.mkdir_p(File.dirname(filename))
94
+ File.write(filename, config.to_yaml)
95
+ rescue StandardError => e
96
+ Bolt::Logger.warn_once('unwriteable_file', "Could not write analytics configuration to #{filename}.")
97
+ # This will get caught by build_client and create a NoopClient
98
+ raise e
99
+ end
100
+
101
+ class Client
102
+ attr_reader :user_id
103
+ attr_accessor :bundled_content
104
+
105
+ def initialize(user_id)
106
+ # lazy-load expensive gem code
107
+ require 'concurrent/configuration'
108
+ require 'concurrent/future'
109
+ require 'httpclient'
110
+ require 'locale'
111
+
112
+ @logger = Bolt::Logger.logger(self)
113
+ @http = HTTPClient.new
114
+ @user_id = user_id
115
+ @executor = Concurrent.global_io_executor
116
+ @os = compute_os
117
+ @bundled_content = {}
118
+ end
119
+
120
+ def screen_view(screen, **kwargs)
121
+ custom_dimensions = Bolt::Util.walk_keys(kwargs) do |k|
122
+ CUSTOM_DIMENSIONS[k] || raise("Unknown analytics key '#{k}'")
123
+ end
124
+
125
+ screen_view_params = {
126
+ # Type
127
+ t: 'screenview',
128
+ # Screen Name
129
+ cd: screen
130
+ }.merge(custom_dimensions)
131
+
132
+ submit(base_params.merge(screen_view_params))
133
+ end
134
+
135
+ def report_bundled_content(mode, name)
136
+ if bundled_content[mode.split.first]&.include?(name)
137
+ event('Bundled Content', mode, label: name)
138
+ end
139
+ end
140
+
141
+ def event(category, action, label: nil, value: nil, **kwargs)
142
+ custom_dimensions = Bolt::Util.walk_keys(kwargs) do |k|
143
+ CUSTOM_DIMENSIONS[k] || raise("Unknown analytics key '#{k}'")
144
+ end
145
+
146
+ event_params = {
147
+ # Type
148
+ t: 'event',
149
+ # Event Category
150
+ ec: category,
151
+ # Event Action
152
+ ea: action
153
+ }.merge(custom_dimensions)
154
+
155
+ # Event Label
156
+ event_params[:el] = label if label
157
+ # Event Value
158
+ event_params[:ev] = value if value
159
+
160
+ submit(base_params.merge(event_params))
161
+ end
162
+
163
+ def submit(params)
164
+ # Handle analytics submission in the background to avoid blocking the
165
+ # app or polluting the log with errors
166
+ Concurrent::Future.execute(executor: @executor) do
167
+ @logger.trace "Submitting analytics: #{JSON.pretty_generate(params)}"
168
+ @http.post(TRACKING_URL, params)
169
+ @logger.trace "Completed analytics submission"
170
+ end
171
+ end
172
+
173
+ # These parameters have terrible names. See this page for complete documentation:
174
+ # https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters
175
+ def base_params
176
+ {
177
+ v: PROTOCOL_VERSION,
178
+ # Client ID
179
+ cid: @user_id,
180
+ # Tracking ID
181
+ tid: TRACKING_ID,
182
+ # Application Name
183
+ an: APPLICATION_NAME,
184
+ # Application Version
185
+ av: Bolt::VERSION,
186
+ # Anonymize IPs
187
+ aip: true,
188
+ # User locale
189
+ ul: Locale.current.to_rfc,
190
+ # Custom Dimension 1 (Operating System)
191
+ cd1: @os
192
+ }
193
+ end
194
+
195
+ def compute_os
196
+ require 'facter'
197
+ os = Facter.value('os')
198
+ "#{os['name']} #{os.dig('release', 'major')}"
199
+ end
200
+
201
+ # If the user is running a very fast command, there may not be time for
202
+ # analytics submission to complete before the command is finished. In
203
+ # that case, we give a little buffer for any stragglers to finish up.
204
+ # 250ms strikes a balance between accomodating slower networks while not
205
+ # introducing a noticeable "hang".
206
+ def finish
207
+ @executor.shutdown
208
+ @executor.wait_for_termination(0.25)
209
+ end
210
+ end
211
+
212
+ class NoopClient
213
+ attr_accessor :bundled_content
214
+
215
+ def initialize
216
+ @logger = Bolt::Logger.logger(self)
217
+ @bundled_content = []
218
+ end
219
+
220
+ def screen_view(screen, **_kwargs)
221
+ @logger.trace "Skipping submission of '#{screen}' screenview because analytics is disabled"
222
+ end
223
+
224
+ def report_bundled_content(mode, name); end
225
+
226
+ def event(category, action, **_kwargs)
227
+ @logger.trace "Skipping submission of '#{category} #{action}' event because analytics is disabled"
228
+ end
229
+
230
+ def finish; end
231
+ end
232
+ end
233
+ end