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,368 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require_relative '../bolt/apply_result'
|
5
|
+
require_relative '../bolt/apply_target'
|
6
|
+
require_relative '../bolt/config'
|
7
|
+
require_relative '../bolt/error'
|
8
|
+
require_relative '../bolt/task'
|
9
|
+
require_relative '../bolt/util/puppet_log_level'
|
10
|
+
require 'find'
|
11
|
+
require 'json'
|
12
|
+
require 'logging'
|
13
|
+
require 'open3'
|
14
|
+
|
15
|
+
module Bolt
|
16
|
+
class Applicator
|
17
|
+
def initialize(inventory, executor, modulepath, plugin_dirs, project,
|
18
|
+
pdb_client, hiera_config, max_compiles, apply_settings)
|
19
|
+
# lazy-load expensive gem code
|
20
|
+
require 'concurrent'
|
21
|
+
@inventory = inventory
|
22
|
+
@executor = executor
|
23
|
+
@modulepath = modulepath || []
|
24
|
+
@plugin_dirs = plugin_dirs
|
25
|
+
@project = project
|
26
|
+
@pdb_client = pdb_client
|
27
|
+
@hiera_config = hiera_config ? validate_hiera_config(hiera_config) : nil
|
28
|
+
@apply_settings = apply_settings || {}
|
29
|
+
|
30
|
+
@pool = Concurrent::ThreadPoolExecutor.new(name: 'apply', max_threads: max_compiles)
|
31
|
+
@logger = Bolt::Logger.logger(self)
|
32
|
+
end
|
33
|
+
|
34
|
+
private def libexec
|
35
|
+
@libexec ||= File.join(Gem::Specification.find_by_name('openbolt').gem_dir, 'libexec')
|
36
|
+
end
|
37
|
+
|
38
|
+
def custom_facts_task
|
39
|
+
@custom_facts_task ||= begin
|
40
|
+
path = File.join(libexec, 'custom_facts.rb')
|
41
|
+
file = { 'name' => 'custom_facts.rb', 'path' => path }
|
42
|
+
metadata = { 'supports_noop' => true, 'input_method' => 'stdin',
|
43
|
+
'implementations' => [
|
44
|
+
{ 'name' => 'custom_facts.rb' },
|
45
|
+
{ 'name' => 'custom_facts.rb', 'remote' => true }
|
46
|
+
] }
|
47
|
+
Bolt::Task.new('apply_helpers::custom_facts', metadata, [file])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def catalog_apply_task
|
52
|
+
@catalog_apply_task ||= begin
|
53
|
+
path = File.join(libexec, 'apply_catalog.rb')
|
54
|
+
file = { 'name' => 'apply_catalog.rb', 'path' => path }
|
55
|
+
metadata = { 'supports_noop' => true, 'input_method' => 'stdin',
|
56
|
+
'implementations' => [
|
57
|
+
{ 'name' => 'apply_catalog.rb' },
|
58
|
+
{ 'name' => 'apply_catalog.rb', 'remote' => true }
|
59
|
+
] }
|
60
|
+
Bolt::Task.new('apply_helpers::apply_catalog', metadata, [file])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def query_resources_task
|
65
|
+
@query_resources_task ||= begin
|
66
|
+
path = File.join(libexec, 'query_resources.rb')
|
67
|
+
file = { 'name' => 'query_resources.rb', 'path' => path }
|
68
|
+
metadata = { 'supports_noop' => true, 'input_method' => 'stdin',
|
69
|
+
'implementations' => [
|
70
|
+
{ 'name' => 'query_resources.rb' },
|
71
|
+
{ 'name' => 'query_resources.rb', 'remote' => true }
|
72
|
+
] }
|
73
|
+
|
74
|
+
Bolt::Task.new('apply_helpers::query_resources', metadata, [file])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def compile(target, scope)
|
79
|
+
# This simplified Puppet node object is what .local uses to determine the
|
80
|
+
# certname of the target
|
81
|
+
node = Puppet::Node.from_data_hash('name' => target.name,
|
82
|
+
'parameters' => { 'clientcert' => target.name })
|
83
|
+
trusted = Puppet::Context::TrustedInformation.local(node)
|
84
|
+
target_data = {
|
85
|
+
name: target.name,
|
86
|
+
facts: @inventory.facts(target).merge('bolt' => true),
|
87
|
+
variables: @inventory.vars(target),
|
88
|
+
trusted: trusted.to_h
|
89
|
+
}
|
90
|
+
catalog_request = scope.merge(target: target_data).merge(future: @executor.future || {})
|
91
|
+
|
92
|
+
bolt_catalog_exe = File.join(libexec, 'bolt_catalog')
|
93
|
+
old_path = ENV['PATH']
|
94
|
+
ENV['PATH'] = "#{RbConfig::CONFIG['bindir']}#{File::PATH_SEPARATOR}#{old_path}"
|
95
|
+
out, err, stat = Open3.capture3('ruby', bolt_catalog_exe, 'compile', stdin_data: catalog_request.to_json)
|
96
|
+
ENV['PATH'] = old_path
|
97
|
+
|
98
|
+
# If bolt_catalog does not return valid JSON, we should print stderr to
|
99
|
+
# see what happened
|
100
|
+
print_logs = stat.success?
|
101
|
+
result = begin
|
102
|
+
JSON.parse(out)
|
103
|
+
rescue JSON::ParserError
|
104
|
+
print_logs = true
|
105
|
+
{ 'message' => "Something's gone terribly wrong! STDERR is logged." }
|
106
|
+
end
|
107
|
+
|
108
|
+
# Any messages logged by Puppet will be on stderr as JSON hashes, so we
|
109
|
+
# parse those and store them here. Any message on stderr that is not
|
110
|
+
# properly JSON formatted is assumed to be an error message. If
|
111
|
+
# compilation was successful, we print the logs as they may include
|
112
|
+
# important warnings. If compilation failed, we don't print the logs as
|
113
|
+
# they are likely redundant with the error that caused the failure, which
|
114
|
+
# will be handled separately.
|
115
|
+
logs = err.lines.map do |line|
|
116
|
+
JSON.parse(line)
|
117
|
+
rescue JSON::ParserError
|
118
|
+
{ 'level' => 'err', 'message' => line }
|
119
|
+
end
|
120
|
+
|
121
|
+
if print_logs
|
122
|
+
logs.each do |log|
|
123
|
+
bolt_level = Bolt::Util::PuppetLogLevel::MAPPING[log['level'].to_sym]
|
124
|
+
message = log['message'].chomp
|
125
|
+
|
126
|
+
case bolt_level
|
127
|
+
when :warn
|
128
|
+
handle_warning(target, message)
|
129
|
+
else
|
130
|
+
@logger.send(bolt_level, "#{target.name}: #{message}")
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
unless stat.success?
|
136
|
+
message = if @apply_settings['trace'] && result['backtrace']
|
137
|
+
([result['message']] + result['backtrace']).join("\n ")
|
138
|
+
else
|
139
|
+
result['message']
|
140
|
+
end
|
141
|
+
raise ApplyError.new(target.name, message)
|
142
|
+
end
|
143
|
+
|
144
|
+
result
|
145
|
+
end
|
146
|
+
|
147
|
+
# Handles logging Puppet warnings, some of which are suppressable.
|
148
|
+
#
|
149
|
+
# @param target [Bolt::Target] The target the apply ran on.
|
150
|
+
# @param message [String] The log message.
|
151
|
+
#
|
152
|
+
private def handle_warning(target, message)
|
153
|
+
# Messages about exported resource declaration and collection, which are
|
154
|
+
# not supported in manifest blocks.
|
155
|
+
if message.include?(Puppet::Pops::Issues::RT_NO_STORECONFIGS_EXPORT.format) ||
|
156
|
+
message.include?(Puppet::Pops::Issues::RT_NO_STORECONFIGS.format)
|
157
|
+
Bolt::Logger.warn('exported_resources', "#{target.name}: #{message}")
|
158
|
+
else
|
159
|
+
@logger.send(:warn, "#{target.name}: #{message}")
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def validate_hiera_config(hiera_config)
|
164
|
+
if File.exist?(File.path(hiera_config))
|
165
|
+
data = File.open(File.path(hiera_config), "r:UTF-8") do |f|
|
166
|
+
if Psych.method(:safe_load).parameters.rassoc(:permitted_classes)
|
167
|
+
YAML.safe_load(f.read, permitted_classes: [Symbol])
|
168
|
+
else
|
169
|
+
YAML.safe_load(f.read, [Symbol])
|
170
|
+
end
|
171
|
+
end
|
172
|
+
if data.nil?
|
173
|
+
return nil
|
174
|
+
elsif data['version'] != 5
|
175
|
+
raise Bolt::ParseError, "Hiera v5 is required, found v#{data['version'] || 3} in #{hiera_config}"
|
176
|
+
end
|
177
|
+
hiera_config
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def apply(args, apply_body, scope)
|
182
|
+
raise(ArgumentError, 'apply requires a TargetSpec') if args.empty?
|
183
|
+
raise(ArgumentError, 'apply requires at least one statement in the apply block') if apply_body.nil?
|
184
|
+
type0 = Puppet.lookup(:pal_script_compiler).type('TargetSpec')
|
185
|
+
Puppet::Pal.assert_type(type0, args[0], 'apply targets')
|
186
|
+
|
187
|
+
@executor.report_function_call('apply')
|
188
|
+
|
189
|
+
options = {}
|
190
|
+
if args.count > 1
|
191
|
+
type1 = Puppet.lookup(:pal_script_compiler).type('Hash[String, Data]')
|
192
|
+
Puppet::Pal.assert_type(type1, args[1], 'apply options')
|
193
|
+
options = args[1].transform_keys { |k| k.sub(/^_/, '').to_sym }
|
194
|
+
end
|
195
|
+
|
196
|
+
plan_vars = scope.to_hash(true, true)
|
197
|
+
|
198
|
+
targets = @inventory.get_targets(args[0])
|
199
|
+
|
200
|
+
apply_ast(apply_body, targets, options, plan_vars)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Count the number of top-level statements in the AST.
|
204
|
+
def count_statements(ast)
|
205
|
+
case ast
|
206
|
+
when Puppet::Pops::Model::Program
|
207
|
+
count_statements(ast.body)
|
208
|
+
when Puppet::Pops::Model::BlockExpression
|
209
|
+
ast.statements.count
|
210
|
+
else
|
211
|
+
1
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def apply_ast(raw_ast, targets, options, plan_vars = {})
|
216
|
+
ast = Puppet::Pops::Serialization::ToDataConverter.convert(raw_ast, rich_data: true, symbol_to_string: true)
|
217
|
+
# Serialize as pcore for *Result* objects
|
218
|
+
plan_vars = Puppet::Pops::Serialization::ToDataConverter.convert(plan_vars,
|
219
|
+
rich_data: true,
|
220
|
+
symbol_as_string: true,
|
221
|
+
type_by_reference: true,
|
222
|
+
local_reference: true)
|
223
|
+
|
224
|
+
scope = {
|
225
|
+
code_ast: ast,
|
226
|
+
modulepath: @modulepath,
|
227
|
+
project: @project.to_h,
|
228
|
+
pdb_config: @pdb_client.instance(options[:puppetdb]).config.to_hash,
|
229
|
+
hiera_config: @hiera_config,
|
230
|
+
plan_vars: plan_vars,
|
231
|
+
# This data isn't available on the target config hash
|
232
|
+
config: @inventory.transport_data_get
|
233
|
+
}.freeze
|
234
|
+
description = options[:description] || 'apply catalog'
|
235
|
+
|
236
|
+
required_modules = options[:required_modules].nil? ? nil : Array(options[:required_modules])
|
237
|
+
if required_modules&.any?
|
238
|
+
@logger.debug("Syncing only required modules: #{required_modules.join(',')}.")
|
239
|
+
end
|
240
|
+
|
241
|
+
@plugin_tarball = Concurrent::Delay.new do
|
242
|
+
build_plugin_tarball do |mod|
|
243
|
+
next unless required_modules.nil? || required_modules.include?(mod.name)
|
244
|
+
search_dirs = []
|
245
|
+
search_dirs << mod.plugins if mod.plugins?
|
246
|
+
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
247
|
+
search_dirs << mod.files if mod.files?
|
248
|
+
search_dirs << mod.scripts if mod.scripts?
|
249
|
+
type_files = "#{mod.path}/types"
|
250
|
+
search_dirs << type_files if File.exist?(type_files)
|
251
|
+
search_dirs
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
r = @executor.log_action(description, targets) do
|
256
|
+
futures = targets.map do |target|
|
257
|
+
Concurrent::Future.execute(executor: @pool) do
|
258
|
+
Thread.current[:name] ||= Thread.current.name
|
259
|
+
@executor.with_node_logging("Compiling manifest block", [target], :trace) do
|
260
|
+
compile(target, scope)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
result_promises = targets.zip(futures).flat_map do |target, future|
|
266
|
+
@executor.queue_execute([target]) do |transport, batch|
|
267
|
+
@executor.with_node_logging("Applying manifest block", batch) do
|
268
|
+
catalog = future.value
|
269
|
+
if future.rejected?
|
270
|
+
batch.map do |batch_target|
|
271
|
+
# If an unhandled exception occurred, wrap it in an ApplyError
|
272
|
+
error = if future.reason.is_a?(Bolt::ApplyError)
|
273
|
+
future.reason
|
274
|
+
else
|
275
|
+
Bolt::ApplyError.new(batch_target, future.reason.message)
|
276
|
+
end
|
277
|
+
|
278
|
+
result = Bolt::ApplyResult.new(batch_target, error: error.to_h)
|
279
|
+
@executor.publish_event(type: :node_result, result: result)
|
280
|
+
result
|
281
|
+
end
|
282
|
+
else
|
283
|
+
arguments = {
|
284
|
+
'catalog' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(catalog),
|
285
|
+
'plugins' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(plugins),
|
286
|
+
'apply_settings' => @apply_settings,
|
287
|
+
# This should just be boltlib and modules dirs shipped with bolt packages
|
288
|
+
# The apply_catalog task uses them to load core types if they exist
|
289
|
+
'bolt_builtin_content' => @modulepath - @plugin_dirs,
|
290
|
+
'_task' => catalog_apply_task.name,
|
291
|
+
'_noop' => options[:noop]
|
292
|
+
}
|
293
|
+
|
294
|
+
callback = proc do |event|
|
295
|
+
if event[:type] == :node_result
|
296
|
+
event = event.merge(result: ApplyResult.from_task_result(event[:result], catalog))
|
297
|
+
end
|
298
|
+
@executor.publish_event(event)
|
299
|
+
end
|
300
|
+
# Respect the run_as default set on the executor
|
301
|
+
options[:run_as] = @executor.run_as if @executor.run_as && !options.key?(:run_as)
|
302
|
+
|
303
|
+
results = transport.batch_task(batch, catalog_apply_task, arguments, options, &callback)
|
304
|
+
Array(results).map { |result| ApplyResult.from_task_result(result, catalog) }
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
@executor.await_results(result_promises)
|
311
|
+
end
|
312
|
+
|
313
|
+
# Allow for report to exclude event metrics (apply_result doesn't require it to be present)
|
314
|
+
resource_counts = r.ok_set.map { |result| result.event_metrics&.fetch('total') }.compact
|
315
|
+
@executor.report_apply(count_statements(raw_ast), resource_counts)
|
316
|
+
|
317
|
+
if !r.ok && !options[:catch_errors]
|
318
|
+
raise Bolt::ApplyFailure, r
|
319
|
+
end
|
320
|
+
r
|
321
|
+
end
|
322
|
+
|
323
|
+
def plugins
|
324
|
+
@plugin_tarball.value ||
|
325
|
+
raise(Bolt::Error.new("Failed to pack module plugins: #{@plugin_tarball.reason}", 'bolt/plugin-error'))
|
326
|
+
end
|
327
|
+
|
328
|
+
def build_plugin_tarball
|
329
|
+
# lazy-load expensive gem code
|
330
|
+
require 'minitar'
|
331
|
+
require 'zlib'
|
332
|
+
|
333
|
+
start_time = Time.now
|
334
|
+
sio = StringIO.new
|
335
|
+
output = Minitar::Output.new(Zlib::GzipWriter.new(sio))
|
336
|
+
|
337
|
+
Puppet.lookup(:current_environment).override_with(modulepath: @plugin_dirs).modules.each do |mod|
|
338
|
+
search_dirs = yield mod
|
339
|
+
|
340
|
+
tar_dir = Pathname.new(mod.name) # goes great with fish
|
341
|
+
mod_dir = Pathname.new(mod.path)
|
342
|
+
files = Find.find(*search_dirs).select { |file| File.file?(file) }
|
343
|
+
|
344
|
+
files.each do |file|
|
345
|
+
tar_path = tar_dir + Pathname.new(file).relative_path_from(mod_dir)
|
346
|
+
@logger.trace("Packing plugin #{file} to #{tar_path}")
|
347
|
+
stat = File.stat(file)
|
348
|
+
content = File.binread(file)
|
349
|
+
output.tar.add_file_simple(
|
350
|
+
tar_path.to_s,
|
351
|
+
data: content,
|
352
|
+
size: content.size,
|
353
|
+
mode: stat.mode & 0o777,
|
354
|
+
mtime: stat.mtime
|
355
|
+
)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
duration = Time.now - start_time
|
360
|
+
@logger.trace("Packed plugins in #{duration * 1000} ms")
|
361
|
+
|
362
|
+
output.close
|
363
|
+
Base64.encode64(sio.string)
|
364
|
+
ensure
|
365
|
+
output&.close
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../bolt/project'
|
4
|
+
require_relative '../bolt/config'
|
5
|
+
require_relative '../bolt/error'
|
6
|
+
|
7
|
+
module Bolt
|
8
|
+
class ApplyInventory
|
9
|
+
class InvalidFunctionCall < Bolt::Error
|
10
|
+
def initialize(function)
|
11
|
+
super("The function '#{function}' is not callable within an apply block",
|
12
|
+
'bolt.inventory/invalid-function-call')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :config_hash
|
17
|
+
|
18
|
+
def initialize(config_hash = {})
|
19
|
+
@config_hash = config_hash
|
20
|
+
@targets = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_apply_target(target)
|
24
|
+
@targets[target.name] = target
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate
|
28
|
+
@groups.validate
|
29
|
+
end
|
30
|
+
|
31
|
+
def version
|
32
|
+
2
|
33
|
+
end
|
34
|
+
|
35
|
+
def target_implementation_class
|
36
|
+
Bolt::ApplyTarget
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_targets(*_params)
|
40
|
+
raise InvalidFunctionCall, 'get_targets'
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_target(*_params)
|
44
|
+
raise InvalidFunctionCall, 'get_target'
|
45
|
+
end
|
46
|
+
|
47
|
+
# rubocop:disable Naming/AccessorMethodName
|
48
|
+
def set_var(*_params)
|
49
|
+
raise InvalidFunctionCall, 'set_var'
|
50
|
+
end
|
51
|
+
|
52
|
+
def set_feature(*_params)
|
53
|
+
raise InvalidFunctionCall, 'set_feature'
|
54
|
+
end
|
55
|
+
# rubocop:enable Naming/AccessorMethodName
|
56
|
+
|
57
|
+
def vars(target)
|
58
|
+
@targets[target.name].vars
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_facts(*_params)
|
62
|
+
raise InvalidFunctionCall, 'add_facts'
|
63
|
+
end
|
64
|
+
|
65
|
+
def facts(target)
|
66
|
+
@targets[target.name].facts
|
67
|
+
end
|
68
|
+
|
69
|
+
def features(target)
|
70
|
+
@targets[target.name].features
|
71
|
+
end
|
72
|
+
|
73
|
+
def resource(target, type, title)
|
74
|
+
@targets[target.name].resource(type, title)
|
75
|
+
end
|
76
|
+
|
77
|
+
def add_to_group(*_params)
|
78
|
+
raise InvalidFunctionCall, 'add_to_group'
|
79
|
+
end
|
80
|
+
|
81
|
+
def plugin_hooks(target)
|
82
|
+
@targets[target.name].plugin_hooks
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_config(_target, _key_or_key_path, _value)
|
86
|
+
raise InvalidFunctionCall, 'set_config'
|
87
|
+
end
|
88
|
+
|
89
|
+
def target_config(target)
|
90
|
+
@targets[target.name].config
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require_relative '../bolt/error'
|
5
|
+
require_relative '../bolt/result'
|
6
|
+
|
7
|
+
module Bolt
|
8
|
+
class ApplyResult < Result
|
9
|
+
def self.puppet_missing_error(result)
|
10
|
+
error_hash = result.error_hash
|
11
|
+
exit_code = error_hash['details']['exit_code'] if error_hash && error_hash['details']
|
12
|
+
# If we get exit code 126 or 127 back, it means the shebang command wasn't found; Puppet isn't present
|
13
|
+
if [126, 127].include?(exit_code)
|
14
|
+
{
|
15
|
+
'msg' => "Puppet is not installed on the target, please install it to enable 'apply'",
|
16
|
+
'kind' => 'bolt/apply-error'
|
17
|
+
}
|
18
|
+
elsif exit_code == 1 &&
|
19
|
+
(error_hash['msg'] =~ /Could not find executable 'ruby.exe'/ ||
|
20
|
+
error_hash['msg'] =~ /The term 'ruby.exe' is not recognized as the name of a cmdlet/)
|
21
|
+
# Windows does not have Ruby present
|
22
|
+
{
|
23
|
+
'msg' => "Puppet was not found on the target or in $env:ProgramFiles, please install it to enable 'apply'",
|
24
|
+
'kind' => 'bolt/apply-error'
|
25
|
+
}
|
26
|
+
elsif exit_code == 1 && error_hash['msg'] =~ /cannot load such file -- puppet \(LoadError\)/
|
27
|
+
# Windows uses a Ruby that doesn't have Puppet installed
|
28
|
+
# TODO: fix so we don't find other Rubies, or point to a known issues URL for more info
|
29
|
+
{ 'msg' => 'Found a Ruby without Puppet present, please install Puppet ' \
|
30
|
+
"or remove Ruby from $env:Path to enable 'apply'",
|
31
|
+
'kind' => 'bolt/apply-error' }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.resource_error(result)
|
36
|
+
if result.value['status'] == 'failed'
|
37
|
+
resources = result.value['resource_statuses']
|
38
|
+
failed = resources.select { |_, r| r['failed'] }.flat_map do |key, resource|
|
39
|
+
resource['events'].select { |e| e['status'] == 'failure' }.map do |event|
|
40
|
+
"\n #{key}: #{event['message']}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
{ 'msg' => "Resources failed to apply for #{result.target.name}#{failed.join}",
|
45
|
+
'kind' => 'bolt/resource-failure' }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.invalid_report_error(result)
|
50
|
+
# These are the keys ApplyResult methods rely on.
|
51
|
+
expected_report_keys = %w[metrics resource_statuses status]
|
52
|
+
missing_keys = expected_report_keys.reject { |k| result.value.include?(k) }
|
53
|
+
|
54
|
+
unless missing_keys.empty?
|
55
|
+
if result['_output']
|
56
|
+
# rubocop:disable Layout/LineLength
|
57
|
+
msg = "Report result contains an '_output' key. Catalog application might have printed extraneous output to stdout: #{result['_output']}"
|
58
|
+
# rubocop:enable Layout/LineLength
|
59
|
+
else
|
60
|
+
msg = "Report did not contain all expected keys missing: #{missing_keys.join(', ')}"
|
61
|
+
end
|
62
|
+
|
63
|
+
{ 'msg' => msg,
|
64
|
+
'kind' => 'bolt/invalid-report' }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.from_task_result(result, catalog = nil)
|
69
|
+
if (puppet_missing = puppet_missing_error(result))
|
70
|
+
new(result.target,
|
71
|
+
error: puppet_missing,
|
72
|
+
report: result.value.reject { |k| k == '_error' },
|
73
|
+
catalog: catalog)
|
74
|
+
elsif !result.ok?
|
75
|
+
new(result.target,
|
76
|
+
error: result.error_hash,
|
77
|
+
catalog: catalog)
|
78
|
+
elsif (invalid_report = invalid_report_error(result))
|
79
|
+
new(result.target,
|
80
|
+
error: invalid_report,
|
81
|
+
report: result.value.reject { |k| %w[_error _output].include?(k) },
|
82
|
+
catalog: catalog)
|
83
|
+
elsif (resource_error = resource_error(result))
|
84
|
+
new(result.target,
|
85
|
+
error: resource_error,
|
86
|
+
report: result.value.reject { |k| k == '_error' },
|
87
|
+
catalog: catalog)
|
88
|
+
else
|
89
|
+
new(result.target,
|
90
|
+
report: result.value,
|
91
|
+
catalog: catalog)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Other pcore methods are inherited from Result
|
96
|
+
def _pcore_init_hash
|
97
|
+
{ 'target' => @target,
|
98
|
+
'error' => value['_error'],
|
99
|
+
'report' => value['report'],
|
100
|
+
'catalog' => catalog }
|
101
|
+
end
|
102
|
+
|
103
|
+
def initialize(target, error: nil, report: nil, catalog: nil)
|
104
|
+
@target = target
|
105
|
+
@value = {}
|
106
|
+
@action = 'apply'
|
107
|
+
@value['report'] = report if report
|
108
|
+
@value['_error'] = error if error
|
109
|
+
@value['_output'] = metrics_message if metrics_message
|
110
|
+
|
111
|
+
if catalog
|
112
|
+
@value['_sensitive'] = Puppet::Pops::Types::PSensitiveType::Sensitive.new({ 'catalog' => catalog })
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def event_metrics
|
117
|
+
if (events = value.dig('report', 'metrics', 'resources', 'values'))
|
118
|
+
events.each_with_object({}) { |ev, h| h[ev[0]] = ev[2] }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def logs
|
123
|
+
value.dig('report', 'logs') || []
|
124
|
+
end
|
125
|
+
|
126
|
+
# Return only log messages associated with resources
|
127
|
+
def resource_logs
|
128
|
+
logs.reject { |log| log['source'] == 'Puppet' }
|
129
|
+
end
|
130
|
+
|
131
|
+
def metrics_message
|
132
|
+
if (metrics = event_metrics)
|
133
|
+
changed = metrics['changed']
|
134
|
+
failed = metrics['failed']
|
135
|
+
skipped = metrics['skipped']
|
136
|
+
unchanged = metrics['total'] - changed - failed - skipped
|
137
|
+
noop = metrics['out_of_sync'] - changed - failed
|
138
|
+
"changed: #{changed}, failed: #{failed}, unchanged: #{unchanged} skipped: #{skipped}, noop: #{noop}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def report
|
143
|
+
@value['report']
|
144
|
+
end
|
145
|
+
|
146
|
+
def catalog
|
147
|
+
sensitive.unwrap['catalog'] if sensitive
|
148
|
+
end
|
149
|
+
|
150
|
+
def generic_value
|
151
|
+
{}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|