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,271 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require 'find'
|
5
|
+
require 'json'
|
6
|
+
require 'pathname'
|
7
|
+
require_relative '../../bolt/transport/base'
|
8
|
+
require_relative 'orch/connection'
|
9
|
+
|
10
|
+
module Bolt
|
11
|
+
module Transport
|
12
|
+
class Orch < Base
|
13
|
+
BOLT_COMMAND_TASK = Struct.new(:name).new('bolt_shim::command').freeze
|
14
|
+
BOLT_SCRIPT_TASK = Struct.new(:name).new('bolt_shim::script').freeze
|
15
|
+
BOLT_UPLOAD_TASK = Struct.new(:name).new('bolt_shim::upload').freeze
|
16
|
+
|
17
|
+
attr_writer :plan_context
|
18
|
+
|
19
|
+
def provided_features
|
20
|
+
['puppet-agent']
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(*args)
|
24
|
+
# lazy-load expensive gem code
|
25
|
+
require 'orchestrator_client'
|
26
|
+
|
27
|
+
@connections = {}
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def finish_plan(result)
|
32
|
+
if result.is_a? Bolt::PlanResult
|
33
|
+
@connections.each_value do |conn|
|
34
|
+
conn.finish_plan(result)
|
35
|
+
rescue StandardError => e
|
36
|
+
@logger.trace("Failed to finish plan on #{conn.key}: #{e.message}")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# It's safe to create connections here for now because the
|
42
|
+
# batches/threads are per connection.
|
43
|
+
def get_connection(conn_opts)
|
44
|
+
key = Connection.get_key(conn_opts)
|
45
|
+
unless (conn = @connections[key])
|
46
|
+
conn = @connections[key] = Connection.new(conn_opts, @plan_context, logger)
|
47
|
+
end
|
48
|
+
conn
|
49
|
+
end
|
50
|
+
|
51
|
+
def process_run_results(targets, results, task_name, position = [])
|
52
|
+
targets_by_name = Hash[targets.map { |t| t.host || t.name }.zip(targets)]
|
53
|
+
results.map do |node_result|
|
54
|
+
target = targets_by_name[node_result['name']]
|
55
|
+
state = node_result['state']
|
56
|
+
result = node_result['result']
|
57
|
+
|
58
|
+
# If it's finished or already has a proper error simply pass it to the
|
59
|
+
# the result otherwise make sure an error is generated
|
60
|
+
if state == 'finished' || (result && result['_error'])
|
61
|
+
if result['_error']
|
62
|
+
unless result['_error'].is_a?(Hash)
|
63
|
+
result['_error'] = { 'kind' => 'puppetlabs.tasks/task-error',
|
64
|
+
'issue_code' => 'TASK_ERROR',
|
65
|
+
'msg' => result['_error'],
|
66
|
+
'details' => {} }
|
67
|
+
end
|
68
|
+
|
69
|
+
result['_error']['details'] ||= {}
|
70
|
+
unless result['_error']['details'].is_a?(Hash)
|
71
|
+
deets = result['_error']['details']
|
72
|
+
result['_error']['details'] = { 'msg' => deets }
|
73
|
+
end
|
74
|
+
file_line = %w[file line].zip(position).to_h.compact
|
75
|
+
result['_error']['details'].merge!(file_line) unless result['_error']['details']['file']
|
76
|
+
end
|
77
|
+
|
78
|
+
Bolt::Result.new(target, value: result, action: 'task', object: task_name)
|
79
|
+
elsif state == 'skipped'
|
80
|
+
details = %w[file line].zip(position).to_h.compact
|
81
|
+
Bolt::Result.new(
|
82
|
+
target,
|
83
|
+
value: { '_error' => {
|
84
|
+
'kind' => 'puppetlabs.tasks/skipped-node',
|
85
|
+
'msg' => "Target #{target.safe_name} was skipped",
|
86
|
+
'details' => details
|
87
|
+
} },
|
88
|
+
action: 'task', object: task_name
|
89
|
+
)
|
90
|
+
else
|
91
|
+
# Make a generic error with a unkown exit_code
|
92
|
+
Bolt::Result.for_task(target, result.to_json, '', 'unknown', task_name, position)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def batch_command(targets, command, options = {}, position = [], &callback)
|
98
|
+
if options[:env_vars] && !options[:env_vars].empty?
|
99
|
+
raise NotImplementedError, "pcp transport does not support setting environment variables"
|
100
|
+
end
|
101
|
+
|
102
|
+
params = {
|
103
|
+
'command' => command
|
104
|
+
}
|
105
|
+
results = run_task_job(targets,
|
106
|
+
BOLT_COMMAND_TASK,
|
107
|
+
params,
|
108
|
+
options,
|
109
|
+
position,
|
110
|
+
&callback)
|
111
|
+
callback ||= proc {}
|
112
|
+
results.map! { |result| unwrap_bolt_result(result.target, result, 'command', command) }
|
113
|
+
results.each do |result|
|
114
|
+
callback.call(type: :node_result, result: result)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def batch_script(targets, script, arguments, options = {}, position = [], &callback)
|
119
|
+
if options[:env_vars] && !options[:env_vars].empty?
|
120
|
+
raise NotImplementedError, "pcp transport does not support setting environment variables"
|
121
|
+
end
|
122
|
+
|
123
|
+
content = File.open(script, &:read)
|
124
|
+
content = Base64.encode64(content)
|
125
|
+
params = {
|
126
|
+
'content' => content,
|
127
|
+
'arguments' => arguments,
|
128
|
+
'name' => Pathname(script).basename.to_s
|
129
|
+
}
|
130
|
+
callback ||= proc {}
|
131
|
+
results = run_task_job(targets, BOLT_SCRIPT_TASK, params, options, position, &callback)
|
132
|
+
results.map! { |result| unwrap_bolt_result(result.target, result, 'script', script) }
|
133
|
+
results.each do |result|
|
134
|
+
callback.call(type: :node_result, result: result)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def pack(directory)
|
139
|
+
# lazy-load expensive gem code
|
140
|
+
require 'minitar'
|
141
|
+
require 'zlib'
|
142
|
+
|
143
|
+
start_time = Time.now
|
144
|
+
io = StringIO.new
|
145
|
+
output = Minitar::Output.new(Zlib::GzipWriter.new(io))
|
146
|
+
Find.find(directory) do |file|
|
147
|
+
next unless File.file?(file)
|
148
|
+
|
149
|
+
tar_path = Pathname.new(file).relative_path_from(Pathname.new(directory))
|
150
|
+
@logger.trace("Packing #{file} to #{tar_path}")
|
151
|
+
stat = File.stat(file)
|
152
|
+
content = File.binread(file)
|
153
|
+
output.tar.add_file_simple(
|
154
|
+
tar_path.to_s,
|
155
|
+
data: content,
|
156
|
+
size: content.size,
|
157
|
+
mode: stat.mode & 0o777,
|
158
|
+
mtime: stat.mtime
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
duration = Time.now - start_time
|
163
|
+
@logger.trace("Packed upload in #{duration * 1000} ms")
|
164
|
+
|
165
|
+
output.close
|
166
|
+
io.string
|
167
|
+
ensure
|
168
|
+
# Closes both tar and sgz.
|
169
|
+
output&.close
|
170
|
+
end
|
171
|
+
|
172
|
+
def batch_upload(targets, source, destination, options = {}, position = [], &callback)
|
173
|
+
stat = File.stat(source)
|
174
|
+
content = if stat.directory?
|
175
|
+
pack(source)
|
176
|
+
else
|
177
|
+
File.open(source, &:read)
|
178
|
+
end
|
179
|
+
content = Base64.encode64(content)
|
180
|
+
mode = File.stat(source).mode
|
181
|
+
params = {
|
182
|
+
'path' => destination,
|
183
|
+
'content' => content,
|
184
|
+
'mode' => mode,
|
185
|
+
'directory' => stat.directory?
|
186
|
+
}
|
187
|
+
callback ||= proc {}
|
188
|
+
results = run_task_job(targets, BOLT_UPLOAD_TASK, params, options, position, &callback)
|
189
|
+
results.map! do |result|
|
190
|
+
if result.error_hash
|
191
|
+
result
|
192
|
+
else
|
193
|
+
Bolt::Result.for_upload(result.target, source, destination)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
results.each do |result|
|
197
|
+
callback&.call(type: :node_result, result: result)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def batch_download(targets, *_args)
|
202
|
+
error = {
|
203
|
+
'kind' => 'bolt/not-supported-error',
|
204
|
+
'msg' => 'pcp transport does not support downloading files',
|
205
|
+
'details' => {}
|
206
|
+
}
|
207
|
+
|
208
|
+
targets.map do |target|
|
209
|
+
Bolt::Result.new(target, error: error, action: 'download')
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def batches(targets)
|
214
|
+
targets.group_by { |target| Connection.get_key(target.options) }.values
|
215
|
+
end
|
216
|
+
|
217
|
+
def run_task_job(targets, task, arguments, options, position)
|
218
|
+
targets.each do |target|
|
219
|
+
yield(type: :node_start, target: target) if block_given?
|
220
|
+
end
|
221
|
+
|
222
|
+
begin
|
223
|
+
# unpack any Sensitive data
|
224
|
+
arguments = unwrap_sensitive_args(arguments)
|
225
|
+
results = get_connection(targets.first.options).run_task(targets, task, arguments, options)
|
226
|
+
|
227
|
+
process_run_results(targets, results, task.name, position)
|
228
|
+
rescue OrchestratorClient::ApiError => e
|
229
|
+
targets.map do |target|
|
230
|
+
Bolt::Result.new(target, error: e.data)
|
231
|
+
end
|
232
|
+
rescue StandardError => e
|
233
|
+
targets.map do |target|
|
234
|
+
Bolt::Result.from_exception(target, e, action: 'task')
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def batch_task(targets, task, arguments, options = {}, position = [], &callback)
|
240
|
+
callback ||= proc {}
|
241
|
+
results = run_task_job(targets, task, arguments, options, position, &callback)
|
242
|
+
results.each do |result|
|
243
|
+
callback.call(type: :node_result, result: result)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def batch_task_with(_targets, _task, _target_mapping, _options = {}, _position = [])
|
248
|
+
raise NotImplementedError, "pcp transport does not support run_task_with()"
|
249
|
+
end
|
250
|
+
|
251
|
+
def batch_connected?(targets)
|
252
|
+
resp = get_connection(targets.first.options).query_inventory(targets)
|
253
|
+
resp['items'].all? { |node| node['connected'] }
|
254
|
+
end
|
255
|
+
|
256
|
+
# run_task generates a result that makes sense for a generic task which
|
257
|
+
# needs to be unwrapped to extract stdout/stderr/exitcode.
|
258
|
+
#
|
259
|
+
def unwrap_bolt_result(target, result, action, obj)
|
260
|
+
if result.error_hash
|
261
|
+
# something went wrong return the failure
|
262
|
+
return result
|
263
|
+
end
|
264
|
+
|
265
|
+
# If we get here, there's no error so we don't need the file or line
|
266
|
+
# number
|
267
|
+
Bolt::Result.for_command(target, result.value, action, obj, [])
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logging'
|
4
|
+
require_relative '../../../bolt/node/errors'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
module Transport
|
8
|
+
class Podman < Docker
|
9
|
+
class Connection < Connection
|
10
|
+
attr_reader :user, :target
|
11
|
+
|
12
|
+
def initialize(target)
|
13
|
+
raise Bolt::ValidationError, "Target #{target.safe_name} does not have a host" unless target.host
|
14
|
+
@target = target
|
15
|
+
@user = ENV['USER'] || Etc.getlogin
|
16
|
+
@logger = Bolt::Logger.logger(target.safe_name)
|
17
|
+
@container_info = {}
|
18
|
+
@logger.trace("Initializing podman connection to #{target.safe_name}")
|
19
|
+
end
|
20
|
+
|
21
|
+
def run_cmd(cmd, env_vars)
|
22
|
+
Bolt::Util.exec_podman(cmd, env_vars)
|
23
|
+
end
|
24
|
+
|
25
|
+
def shell
|
26
|
+
@shell ||= if Bolt::Util.windows?
|
27
|
+
Bolt::Shell::Powershell.new(target, self)
|
28
|
+
else
|
29
|
+
Bolt::Shell::Bash.new(target, self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def reset_cwd?
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def connect
|
38
|
+
# We don't actually have a connection, but we do need to
|
39
|
+
# check that the container exists and is running.
|
40
|
+
ps = execute_local_json_command('ps')
|
41
|
+
container = Array(ps).find { |item|
|
42
|
+
item["ID"].to_s.eql?(@target.host) ||
|
43
|
+
item["Id"].to_s.start_with?(@target.host) ||
|
44
|
+
Array(item["Names"]).include?(@target.host)
|
45
|
+
}
|
46
|
+
raise "Could not find a container with name or ID matching '#{@target.host}'" if container.nil?
|
47
|
+
# Now find the indepth container information
|
48
|
+
id = container["ID"] || container["Id"]
|
49
|
+
output = execute_local_json_command('inspect', [id])
|
50
|
+
# Store the container information for later
|
51
|
+
@container_info = output.first
|
52
|
+
@logger.trace { "Opened session" }
|
53
|
+
true
|
54
|
+
rescue StandardError => e
|
55
|
+
raise Bolt::Node::ConnectError.new(
|
56
|
+
"Failed to connect to #{target.safe_name}: #{e.message}",
|
57
|
+
'CONNECT_ERROR'
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Executes a command inside the target container. This is called from the shell class.
|
62
|
+
#
|
63
|
+
# @param command [string] The command to run
|
64
|
+
def execute(command)
|
65
|
+
args = []
|
66
|
+
args += %w[--interactive]
|
67
|
+
args += %w[--tty] if target.options['tty']
|
68
|
+
args += @env_vars if @env_vars
|
69
|
+
|
70
|
+
if target.options['shell-command'] && !target.options['shell-command'].empty?
|
71
|
+
# escape any double quotes in command
|
72
|
+
command = command.gsub('"', '\"')
|
73
|
+
command = "#{target.options['shell-command']} \"#{command}\""
|
74
|
+
end
|
75
|
+
|
76
|
+
podman_command = %w[podman exec] + args + [container_id] + Shellwords.split(command)
|
77
|
+
@logger.trace { "Executing: #{podman_command.join(' ')}" }
|
78
|
+
|
79
|
+
Open3.popen3(*podman_command)
|
80
|
+
rescue StandardError
|
81
|
+
@logger.trace { "Command aborted" }
|
82
|
+
raise
|
83
|
+
end
|
84
|
+
|
85
|
+
# Converts the JSON encoded STDOUT string from the podman cli into ruby objects
|
86
|
+
#
|
87
|
+
# @param stdout [String] The string to convert
|
88
|
+
# @return [Object] Ruby object representation of the JSON string
|
89
|
+
private def extract_json(stdout)
|
90
|
+
# Podman renders the output in pretty JSON, which results in a newline
|
91
|
+
# appearing in the output before the closing bracket.
|
92
|
+
# should we only get a single line with no newline at all, we also
|
93
|
+
# assume it is a single minified JSON object
|
94
|
+
stdout.strip!
|
95
|
+
newline = stdout.index("\n") || -1
|
96
|
+
bracket = stdout.index('}') || -1
|
97
|
+
JSON.parse(stdout) if bracket > newline
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'shellwords'
|
5
|
+
require_relative '../../bolt/transport/base'
|
6
|
+
|
7
|
+
module Bolt
|
8
|
+
module Transport
|
9
|
+
class Podman < Docker
|
10
|
+
def with_connection(target)
|
11
|
+
conn = Connection.new(target)
|
12
|
+
conn.connect
|
13
|
+
yield conn
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require_relative 'podman/connection'
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../bolt/task'
|
4
|
+
require_relative '../../bolt/transport/base'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
module Transport
|
8
|
+
class Remote < Base
|
9
|
+
# TODO: this should have access to inventory so target doesn't have to
|
10
|
+
def initialize(executor)
|
11
|
+
super()
|
12
|
+
|
13
|
+
@executor = executor
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_proxy(target)
|
17
|
+
inventory = target.inventory
|
18
|
+
raise "Target was created without inventory? Not get_targets?" unless inventory
|
19
|
+
proxy = inventory.get_targets(target.options['run-on'] || 'localhost').first
|
20
|
+
|
21
|
+
if proxy.transport == 'remote'
|
22
|
+
msg = "#{proxy.name} is not a valid run-on target for #{target.name} since is also remote."
|
23
|
+
raise Bolt::Error.new(msg, 'bolt/invalid-remote-target')
|
24
|
+
end
|
25
|
+
proxy
|
26
|
+
end
|
27
|
+
|
28
|
+
# Cannot batch because arugments differ
|
29
|
+
def run_task(target, task, arguments, options = {}, position = [])
|
30
|
+
proxy_target = get_proxy(target)
|
31
|
+
transport = @executor.transport(proxy_target.transport)
|
32
|
+
arguments = arguments.merge('_target' => target.to_h.compact)
|
33
|
+
|
34
|
+
remote_task = task.remote_instance
|
35
|
+
|
36
|
+
result = transport.run_task(proxy_target, remote_task, arguments, options, position)
|
37
|
+
Bolt::Result.new(target, value: result.value, action: 'task', object: task.name)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logging'
|
4
|
+
require_relative '../../bolt/result'
|
5
|
+
require_relative '../../bolt/shell'
|
6
|
+
require_relative '../../bolt/transport/base'
|
7
|
+
|
8
|
+
module Bolt
|
9
|
+
module Transport
|
10
|
+
# A simple transport has a single connection per target and delegates its
|
11
|
+
# operation to a target-specific shell.
|
12
|
+
class Simple < Base
|
13
|
+
def with_connection(_target)
|
14
|
+
raise NotImplementedError, "with_connection() must be implemented by the transport class"
|
15
|
+
end
|
16
|
+
|
17
|
+
def connected?(target)
|
18
|
+
with_connection(target) { true }
|
19
|
+
rescue Bolt::Node::ConnectError
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
def run_command(target, command, options = {}, position = [])
|
24
|
+
with_connection(target) do |conn|
|
25
|
+
conn.shell.run_command(command, options, position)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def upload(target, source, destination, options = {})
|
30
|
+
with_connection(target) do |conn|
|
31
|
+
conn.shell.upload(source, destination, options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def download(target, source, destination, options = {})
|
36
|
+
with_connection(target) do |conn|
|
37
|
+
conn.shell.download(source, destination, options)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def run_script(target, script, arguments, options = {}, position = [])
|
42
|
+
with_connection(target) do |conn|
|
43
|
+
conn.shell.run_script(script, arguments, options, position)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def run_task(target, task, arguments, options = {}, position = [])
|
48
|
+
with_connection(target) do |conn|
|
49
|
+
conn.shell.run_task(task, arguments, options, position)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|