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.
- checksums.yaml +7 -0
- data/Puppetfile +52 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +60 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/containerresult.rb +51 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/future.rb +25 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +71 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +55 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb +65 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/target.rb +93 -0
- data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +33 -0
- data/bolt-modules/boltlib/lib/puppet/functions/add_to_group.rb +38 -0
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +208 -0
- data/bolt-modules/boltlib/lib/puppet/functions/background.rb +62 -0
- data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +57 -0
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +130 -0
- data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +31 -0
- data/bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb +52 -0
- data/bolt-modules/boltlib/lib/puppet/functions/get_resources.rb +87 -0
- data/bolt-modules/boltlib/lib/puppet/functions/get_target.rb +34 -0
- data/bolt-modules/boltlib/lib/puppet/functions/get_targets.rb +35 -0
- data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +74 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_command.rb +97 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb +47 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +52 -0
- data/bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb +40 -0
- data/bolt-modules/boltlib/lib/puppet/functions/resolve_references.rb +42 -0
- data/bolt-modules/boltlib/lib/puppet/functions/resource.rb +53 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +106 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_container.rb +162 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +291 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +145 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +164 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +211 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_config.rb +48 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_feature.rb +43 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_resources.rb +145 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_var.rb +38 -0
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +101 -0
- data/bolt-modules/boltlib/lib/puppet/functions/vars.rb +29 -0
- data/bolt-modules/boltlib/lib/puppet/functions/wait.rb +131 -0
- data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +59 -0
- data/bolt-modules/boltlib/lib/puppet/functions/without_default_logging.rb +39 -0
- data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +50 -0
- data/bolt-modules/boltlib/types/planresult.pp +18 -0
- data/bolt-modules/boltlib/types/targetspec.pp +7 -0
- data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +42 -0
- data/bolt-modules/ctrl/lib/puppet/functions/ctrl/sleep.rb +20 -0
- data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +35 -0
- data/bolt-modules/file/lib/puppet/functions/file/delete.rb +21 -0
- data/bolt-modules/file/lib/puppet/functions/file/exists.rb +28 -0
- data/bolt-modules/file/lib/puppet/functions/file/join.rb +20 -0
- data/bolt-modules/file/lib/puppet/functions/file/read.rb +33 -0
- data/bolt-modules/file/lib/puppet/functions/file/readable.rb +28 -0
- data/bolt-modules/file/lib/puppet/functions/file/write.rb +24 -0
- data/bolt-modules/log/lib/puppet/functions/log/debug.rb +39 -0
- data/bolt-modules/log/lib/puppet/functions/log/error.rb +40 -0
- data/bolt-modules/log/lib/puppet/functions/log/fatal.rb +40 -0
- data/bolt-modules/log/lib/puppet/functions/log/info.rb +39 -0
- data/bolt-modules/log/lib/puppet/functions/log/trace.rb +39 -0
- data/bolt-modules/log/lib/puppet/functions/log/warn.rb +41 -0
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +36 -0
- data/bolt-modules/out/lib/puppet/functions/out/verbose.rb +35 -0
- data/bolt-modules/prompt/lib/puppet/functions/prompt/menu.rb +103 -0
- data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +65 -0
- data/bolt-modules/system/lib/puppet/functions/system/env.rb +20 -0
- data/exe/bolt +17 -0
- data/guides/debugging.yaml +27 -0
- data/guides/inventory.yaml +23 -0
- data/guides/links.yaml +12 -0
- data/guides/logging.yaml +17 -0
- data/guides/module.yaml +18 -0
- data/guides/modulepath.yaml +24 -0
- data/guides/project.yaml +21 -0
- data/guides/targets.yaml +28 -0
- data/guides/transports.yaml +22 -0
- data/lib/bolt/analytics.rb +233 -0
- data/lib/bolt/application.rb +806 -0
- data/lib/bolt/applicator.rb +368 -0
- data/lib/bolt/apply_inventory.rb +93 -0
- data/lib/bolt/apply_result.rb +154 -0
- data/lib/bolt/apply_target.rb +90 -0
- data/lib/bolt/bolt_option_parser.rb +1226 -0
- data/lib/bolt/catalog/logging.rb +15 -0
- data/lib/bolt/catalog.rb +144 -0
- data/lib/bolt/cli.rb +949 -0
- data/lib/bolt/config/modulepath.rb +30 -0
- data/lib/bolt/config/options.rb +673 -0
- data/lib/bolt/config/transport/base.rb +133 -0
- data/lib/bolt/config/transport/docker.rb +34 -0
- data/lib/bolt/config/transport/jail.rb +33 -0
- data/lib/bolt/config/transport/local.rb +39 -0
- data/lib/bolt/config/transport/lxd.rb +34 -0
- data/lib/bolt/config/transport/options.rb +431 -0
- data/lib/bolt/config/transport/orch.rb +41 -0
- data/lib/bolt/config/transport/podman.rb +33 -0
- data/lib/bolt/config/transport/remote.rb +24 -0
- data/lib/bolt/config/transport/ssh.rb +138 -0
- data/lib/bolt/config/transport/winrm.rb +63 -0
- data/lib/bolt/config.rb +515 -0
- data/lib/bolt/container_result.rb +105 -0
- data/lib/bolt/error.rb +194 -0
- data/lib/bolt/executor.rb +539 -0
- data/lib/bolt/fiber_executor.rb +190 -0
- data/lib/bolt/inventory/group.rb +446 -0
- data/lib/bolt/inventory/inventory.rb +391 -0
- data/lib/bolt/inventory/options.rb +139 -0
- data/lib/bolt/inventory/target.rb +293 -0
- data/lib/bolt/inventory.rb +120 -0
- data/lib/bolt/logger.rb +252 -0
- data/lib/bolt/module.rb +54 -0
- data/lib/bolt/module_installer/installer.rb +44 -0
- data/lib/bolt/module_installer/puppetfile/forge_module.rb +54 -0
- data/lib/bolt/module_installer/puppetfile/git_module.rb +37 -0
- data/lib/bolt/module_installer/puppetfile/module.rb +26 -0
- data/lib/bolt/module_installer/puppetfile.rb +131 -0
- data/lib/bolt/module_installer/resolver.rb +129 -0
- data/lib/bolt/module_installer/specs/forge_spec.rb +91 -0
- data/lib/bolt/module_installer/specs/git_spec.rb +150 -0
- data/lib/bolt/module_installer/specs/id/base.rb +116 -0
- data/lib/bolt/module_installer/specs/id/gitclone.rb +120 -0
- data/lib/bolt/module_installer/specs/id/github.rb +90 -0
- data/lib/bolt/module_installer/specs/id/gitlab.rb +92 -0
- data/lib/bolt/module_installer/specs.rb +95 -0
- data/lib/bolt/module_installer.rb +208 -0
- data/lib/bolt/node/errors.rb +55 -0
- data/lib/bolt/node/output.rb +29 -0
- data/lib/bolt/outputter/human.rb +958 -0
- data/lib/bolt/outputter/json.rb +205 -0
- data/lib/bolt/outputter/logger.rb +76 -0
- data/lib/bolt/outputter/rainbow.rb +118 -0
- data/lib/bolt/outputter.rb +57 -0
- data/lib/bolt/pal/issues.rb +19 -0
- data/lib/bolt/pal/logging.rb +17 -0
- data/lib/bolt/pal/yaml_plan/evaluator.rb +83 -0
- data/lib/bolt/pal/yaml_plan/loader.rb +94 -0
- data/lib/bolt/pal/yaml_plan/parameter.rb +63 -0
- data/lib/bolt/pal/yaml_plan/step/command.rb +45 -0
- data/lib/bolt/pal/yaml_plan/step/download.rb +37 -0
- data/lib/bolt/pal/yaml_plan/step/eval.rb +42 -0
- data/lib/bolt/pal/yaml_plan/step/message.rb +31 -0
- data/lib/bolt/pal/yaml_plan/step/plan.rb +42 -0
- data/lib/bolt/pal/yaml_plan/step/resources.rb +170 -0
- data/lib/bolt/pal/yaml_plan/step/script.rb +62 -0
- data/lib/bolt/pal/yaml_plan/step/task.rb +42 -0
- data/lib/bolt/pal/yaml_plan/step/upload.rb +37 -0
- data/lib/bolt/pal/yaml_plan/step/verbose.rb +31 -0
- data/lib/bolt/pal/yaml_plan/step.rb +223 -0
- data/lib/bolt/pal/yaml_plan/transpiler.rb +90 -0
- data/lib/bolt/pal/yaml_plan.rb +172 -0
- data/lib/bolt/pal.rb +847 -0
- data/lib/bolt/plan_creator.rb +219 -0
- data/lib/bolt/plan_future.rb +86 -0
- data/lib/bolt/plan_result.rb +44 -0
- data/lib/bolt/plugin/cache.rb +76 -0
- data/lib/bolt/plugin/env_var.rb +54 -0
- data/lib/bolt/plugin/module.rb +276 -0
- data/lib/bolt/plugin/prompt.rb +36 -0
- data/lib/bolt/plugin/puppet_connect_data.rb +84 -0
- data/lib/bolt/plugin/puppetdb.rb +124 -0
- data/lib/bolt/plugin/task.rb +72 -0
- data/lib/bolt/plugin.rb +380 -0
- data/lib/bolt/project.rb +219 -0
- data/lib/bolt/project_manager/config_migrator.rb +113 -0
- data/lib/bolt/project_manager/inventory_migrator.rb +67 -0
- data/lib/bolt/project_manager/migrator.rb +39 -0
- data/lib/bolt/project_manager/module_migrator.rb +203 -0
- data/lib/bolt/project_manager.rb +221 -0
- data/lib/bolt/puppetdb/client.rb +153 -0
- data/lib/bolt/puppetdb/config.rb +176 -0
- data/lib/bolt/puppetdb/instance.rb +146 -0
- data/lib/bolt/puppetdb.rb +15 -0
- data/lib/bolt/r10k_log_proxy.rb +30 -0
- data/lib/bolt/rerun.rb +55 -0
- data/lib/bolt/resource_instance.rb +133 -0
- data/lib/bolt/result.rb +247 -0
- data/lib/bolt/result_set.rb +128 -0
- data/lib/bolt/shell/bash/tmpdir.rb +62 -0
- data/lib/bolt/shell/bash.rb +516 -0
- data/lib/bolt/shell/powershell/snippets.rb +181 -0
- data/lib/bolt/shell/powershell.rb +365 -0
- data/lib/bolt/shell.rb +105 -0
- data/lib/bolt/target.rb +174 -0
- data/lib/bolt/task/puppet_server.rb +27 -0
- data/lib/bolt/task/run.rb +55 -0
- data/lib/bolt/task.rb +163 -0
- data/lib/bolt/transport/base.rb +252 -0
- data/lib/bolt/transport/docker/connection.rb +150 -0
- data/lib/bolt/transport/docker.rb +23 -0
- data/lib/bolt/transport/jail/connection.rb +81 -0
- data/lib/bolt/transport/jail.rb +21 -0
- data/lib/bolt/transport/local/connection.rb +106 -0
- data/lib/bolt/transport/local.rb +20 -0
- data/lib/bolt/transport/lxd/connection.rb +115 -0
- data/lib/bolt/transport/lxd.rb +26 -0
- data/lib/bolt/transport/orch/connection.rb +111 -0
- data/lib/bolt/transport/orch.rb +271 -0
- data/lib/bolt/transport/podman/connection.rb +102 -0
- data/lib/bolt/transport/podman.rb +19 -0
- data/lib/bolt/transport/remote.rb +41 -0
- data/lib/bolt/transport/simple.rb +54 -0
- data/lib/bolt/transport/ssh/connection.rb +321 -0
- data/lib/bolt/transport/ssh/exec_connection.rb +140 -0
- data/lib/bolt/transport/ssh.rb +48 -0
- data/lib/bolt/transport/winrm/connection.rb +378 -0
- data/lib/bolt/transport/winrm.rb +33 -0
- data/lib/bolt/util/format.rb +68 -0
- data/lib/bolt/util/puppet_log_level.rb +21 -0
- data/lib/bolt/util.rb +465 -0
- data/lib/bolt/validator.rb +227 -0
- data/lib/bolt/version.rb +5 -0
- data/lib/bolt.rb +8 -0
- data/lib/bolt_server/acl.rb +39 -0
- data/lib/bolt_server/base_config.rb +112 -0
- data/lib/bolt_server/config.rb +64 -0
- data/lib/bolt_server/file_cache.rb +200 -0
- data/lib/bolt_server/request_error.rb +11 -0
- data/lib/bolt_server/schemas/action-check_node_connections.json +14 -0
- data/lib/bolt_server/schemas/action-run_command.json +12 -0
- data/lib/bolt_server/schemas/action-run_script.json +47 -0
- data/lib/bolt_server/schemas/action-run_task.json +20 -0
- data/lib/bolt_server/schemas/action-upload_file.json +47 -0
- data/lib/bolt_server/schemas/partials/target-any.json +10 -0
- data/lib/bolt_server/schemas/partials/target-ssh.json +88 -0
- data/lib/bolt_server/schemas/partials/target-winrm.json +67 -0
- data/lib/bolt_server/schemas/partials/task.json +94 -0
- data/lib/bolt_server/schemas/transport-ssh.json +25 -0
- data/lib/bolt_server/schemas/transport-winrm.json +19 -0
- data/lib/bolt_server/transport_app.rb +554 -0
- data/lib/bolt_spec/bolt_context.rb +226 -0
- data/lib/bolt_spec/plans/action_stubs/command_stub.rb +51 -0
- data/lib/bolt_spec/plans/action_stubs/download_stub.rb +66 -0
- data/lib/bolt_spec/plans/action_stubs/plan_stub.rb +55 -0
- data/lib/bolt_spec/plans/action_stubs/script_stub.rb +59 -0
- data/lib/bolt_spec/plans/action_stubs/task_stub.rb +57 -0
- data/lib/bolt_spec/plans/action_stubs/upload_stub.rb +65 -0
- data/lib/bolt_spec/plans/action_stubs.rb +196 -0
- data/lib/bolt_spec/plans/mock_executor.rb +361 -0
- data/lib/bolt_spec/plans/publish_stub.rb +49 -0
- data/lib/bolt_spec/plans.rb +190 -0
- data/lib/bolt_spec/run.rb +246 -0
- data/lib/logging_extensions/logging.rb +13 -0
- data/libexec/apply_catalog.rb +130 -0
- data/libexec/bolt_catalog +68 -0
- data/libexec/custom_facts.rb +63 -0
- data/libexec/query_resources.rb +75 -0
- data/modules/aggregate/lib/puppet/functions/aggregate/count.rb +21 -0
- data/modules/aggregate/lib/puppet/functions/aggregate/nodes.rb +22 -0
- data/modules/aggregate/lib/puppet/functions/aggregate/targets.rb +21 -0
- data/modules/aggregate/plans/count.pp +56 -0
- data/modules/aggregate/plans/targets.pp +56 -0
- data/modules/canary/lib/puppet/functions/canary/merge.rb +13 -0
- data/modules/canary/lib/puppet/functions/canary/random_split.rb +22 -0
- data/modules/canary/lib/puppet/functions/canary/skip.rb +25 -0
- data/modules/canary/plans/init.pp +100 -0
- data/modules/puppet_connect/plans/test_input_data.pp +94 -0
- data/modules/puppetdb_fact/plans/init.pp +20 -0
- data/resources/bolt_bash_completion.sh +214 -0
- 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
|