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,321 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logging'
|
4
|
+
require 'shellwords'
|
5
|
+
require_relative '../../../bolt/node/errors'
|
6
|
+
require_relative '../../../bolt/node/output'
|
7
|
+
require_relative '../../../bolt/util'
|
8
|
+
|
9
|
+
module Bolt
|
10
|
+
module Transport
|
11
|
+
class SSH < Simple
|
12
|
+
class Connection
|
13
|
+
attr_reader :logger, :user, :target
|
14
|
+
|
15
|
+
def initialize(target, transport_logger)
|
16
|
+
# lazy-load expensive gem code
|
17
|
+
require 'net/ssh'
|
18
|
+
require 'net/ssh/proxy/jump'
|
19
|
+
|
20
|
+
raise Bolt::ValidationError, "Target #{target.safe_name} does not have a host" unless target.host
|
21
|
+
|
22
|
+
@target = target
|
23
|
+
@load_config = target.options['load-config']
|
24
|
+
|
25
|
+
ssh_config = @load_config ? Net::SSH::Config.for(target.host) : {}
|
26
|
+
@user = @target.user || ssh_config[:user] || Etc.getlogin
|
27
|
+
@strict_host_key_checking = ssh_config[:strict_host_key_checking]
|
28
|
+
|
29
|
+
@logger = Bolt::Logger.logger(@target.safe_name)
|
30
|
+
@transport_logger = transport_logger
|
31
|
+
@logger.trace("Initializing ssh connection to #{@target.safe_name}")
|
32
|
+
|
33
|
+
if target.options['private-key'].instance_of?(String)
|
34
|
+
begin
|
35
|
+
Bolt::Util.validate_file('ssh key', target.options['private-key'])
|
36
|
+
rescue Bolt::FileError => e
|
37
|
+
Bolt::Logger.warn("invalid_ssh_key", e.msg)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def connect
|
43
|
+
options = {
|
44
|
+
logger: @transport_logger,
|
45
|
+
non_interactive: true
|
46
|
+
}
|
47
|
+
|
48
|
+
if (key = target.options['private-key'])
|
49
|
+
if key.instance_of?(String)
|
50
|
+
options[:keys] = key
|
51
|
+
else
|
52
|
+
options[:key_data] = [key['key-data']]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
options[:port] = target.port if target.port
|
57
|
+
options[:password] = target.password if target.password
|
58
|
+
# Support both net-ssh 4 and 5. We use 5 in packaging, but Beaker pins to 4 so we
|
59
|
+
# want the gem to be compatible with version 4.
|
60
|
+
options[:verify_host_key] = if target.options['host-key-check'].nil?
|
61
|
+
# Fall back to SSH behavior. This variable will only be set in net-ssh 5.3+.
|
62
|
+
if @strict_host_key_checking.nil? || @strict_host_key_checking
|
63
|
+
net_ssh_verifier(:always)
|
64
|
+
else
|
65
|
+
# SSH's behavior with StrictHostKeyChecking=no: adds new keys to known_hosts.
|
66
|
+
# If known_hosts points to /dev/null, then equivalent to :never where it
|
67
|
+
# accepts any key beacuse they're all new.
|
68
|
+
net_ssh_verifier(:accept_new_or_tunnel_local)
|
69
|
+
end
|
70
|
+
elsif target.options['host-key-check']
|
71
|
+
net_ssh_verifier(:always)
|
72
|
+
else
|
73
|
+
net_ssh_verifier(:never)
|
74
|
+
end
|
75
|
+
options[:timeout] = target.options['connect-timeout'] if target.options['connect-timeout']
|
76
|
+
|
77
|
+
options[:proxy] = Net::SSH::Proxy::Jump.new(target.options['proxyjump']) if target.options['proxyjump']
|
78
|
+
|
79
|
+
# Override the default supported algorithms for net-ssh. By default, a subset of supported algorithms
|
80
|
+
# are enabled in 6.x, while several are deprecated and not enabled by default. The *-algorithms
|
81
|
+
# options can be used to specify a list of algorithms to enable in net-ssh. Any algorithms not in the
|
82
|
+
# list are disabled, including ones that are normally enabled by default. Support for deprecated
|
83
|
+
# algorithms will be removed in 7.x.
|
84
|
+
# https://github.com/net-ssh/net-ssh#supported-algorithms
|
85
|
+
if target.options['encryption-algorithms']
|
86
|
+
options[:encryption] = net_ssh_algorithms(:encryption, target.options['encryption-algorithms'])
|
87
|
+
end
|
88
|
+
|
89
|
+
if target.options['host-key-algorithms']
|
90
|
+
options[:host_key] = net_ssh_algorithms(:host_key, target.options['host-key-algorithms'])
|
91
|
+
end
|
92
|
+
|
93
|
+
if target.options['kex-algorithms']
|
94
|
+
options[:kex] = net_ssh_algorithms(:kex, target.options['kex-algorithms'])
|
95
|
+
end
|
96
|
+
|
97
|
+
if target.options['mac-algorithms']
|
98
|
+
options[:hmac] = net_ssh_algorithms(:hmac, target.options['mac-algorithms'])
|
99
|
+
end
|
100
|
+
|
101
|
+
# This option was to address discrepency betwen net-ssh host-key-check and ssh(1)
|
102
|
+
# For the net-ssh 5.x series it defaults to true, in 6.x it will default to false, and will be removed in 7.x
|
103
|
+
# https://github.com/net-ssh/net-ssh/pull/663#issuecomment-469979931
|
104
|
+
options[:check_host_ip] = false if Net::SSH::VALID_OPTIONS.include?(:check_host_ip)
|
105
|
+
|
106
|
+
if @load_config
|
107
|
+
# Mirroring:
|
108
|
+
# https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/authentication/agent.rb#L80
|
109
|
+
# https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/authentication/pageant.rb#L403
|
110
|
+
if defined?(UNIXSocket) && UNIXSocket
|
111
|
+
if ENV['SSH_AUTH_SOCK'].to_s.empty?
|
112
|
+
@logger.debug { "Disabling use_agent in net-ssh: ssh-agent is not available" }
|
113
|
+
options[:use_agent] = false
|
114
|
+
end
|
115
|
+
elsif Bolt::Util.windows?
|
116
|
+
pageant = Net::SSH::Authentication::Pageant::Win.FindWindow("Pageant", "Pageant")
|
117
|
+
# If pageant is not running
|
118
|
+
if pageant.to_i == 0
|
119
|
+
@logger.debug { "Disabling use_agent in net-ssh: pageant process not running" }
|
120
|
+
options[:use_agent] = false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
else
|
124
|
+
# Disable ssh config and ssh-agent if requested via load_config
|
125
|
+
options[:config] = false
|
126
|
+
options[:use_agent] = false
|
127
|
+
end
|
128
|
+
|
129
|
+
@session = Net::SSH.start(target.host, @user, options)
|
130
|
+
validate_ssh_version
|
131
|
+
@logger.trace { "Opened session" }
|
132
|
+
rescue Net::SSH::AuthenticationFailed => e
|
133
|
+
raise Bolt::Node::ConnectError.new(
|
134
|
+
e.message,
|
135
|
+
'AUTH_ERROR'
|
136
|
+
)
|
137
|
+
rescue Net::SSH::HostKeyError => e
|
138
|
+
raise Bolt::Node::ConnectError.new(
|
139
|
+
"Host key verification failed for #{target.safe_name}: #{e.message}",
|
140
|
+
'HOST_KEY_ERROR'
|
141
|
+
)
|
142
|
+
rescue Net::SSH::ConnectionTimeout
|
143
|
+
raise Bolt::Node::ConnectError.new(
|
144
|
+
"Timeout after #{target.options['connect-timeout']} seconds connecting to #{target.safe_name}",
|
145
|
+
'CONNECT_ERROR'
|
146
|
+
)
|
147
|
+
rescue StandardError => e
|
148
|
+
raise Bolt::Node::ConnectError.new(
|
149
|
+
"Failed to connect to #{target.safe_name}: #{e.message}",
|
150
|
+
'CONNECT_ERROR'
|
151
|
+
)
|
152
|
+
end
|
153
|
+
|
154
|
+
def disconnect
|
155
|
+
if @session && !@session.closed?
|
156
|
+
begin
|
157
|
+
Timeout.timeout(@target.options['disconnect-timeout']) { @session.close }
|
158
|
+
rescue Timeout::Error
|
159
|
+
@session.shutdown!
|
160
|
+
end
|
161
|
+
@logger.trace { "Closed session" }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def execute(command_str)
|
166
|
+
in_rd, in_wr = IO.pipe
|
167
|
+
out_rd, out_wr = IO.pipe
|
168
|
+
err_rd, err_wr = IO.pipe
|
169
|
+
th = Thread.new do
|
170
|
+
exit_code = nil
|
171
|
+
session_channel = @session.open_channel do |channel|
|
172
|
+
# Request a pseudo tty
|
173
|
+
channel.request_pty if target.options['tty']
|
174
|
+
|
175
|
+
channel.exec(command_str) do |_, success|
|
176
|
+
unless success
|
177
|
+
raise Bolt::Node::ConnectError.new(
|
178
|
+
"Could not execute command: #{command_str.inspect}",
|
179
|
+
'EXEC_ERROR'
|
180
|
+
)
|
181
|
+
end
|
182
|
+
|
183
|
+
channel.on_data do |_, data|
|
184
|
+
out_wr << data
|
185
|
+
end
|
186
|
+
|
187
|
+
channel.on_extended_data do |_, _, data|
|
188
|
+
err_wr << data
|
189
|
+
end
|
190
|
+
|
191
|
+
channel.on_request("exit-status") do |_, data|
|
192
|
+
exit_code = data.read_long
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
write_th = Thread.new do
|
197
|
+
chunk_size = 4096
|
198
|
+
eof = false
|
199
|
+
active = true
|
200
|
+
readable = false
|
201
|
+
while active && !eof
|
202
|
+
@session.loop(0.1) do
|
203
|
+
active = session_channel.active?
|
204
|
+
readable = select([in_rd], [], [], 0)
|
205
|
+
# Loop as long as the channel is still live and there's nothing to be written
|
206
|
+
active && !readable
|
207
|
+
end
|
208
|
+
if readable
|
209
|
+
if in_rd.eof?
|
210
|
+
session_channel.eof!
|
211
|
+
eof = true
|
212
|
+
else
|
213
|
+
to_write = in_rd.readpartial(chunk_size)
|
214
|
+
session_channel.send_data(to_write)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
session_channel.wait
|
219
|
+
end
|
220
|
+
write_th.join
|
221
|
+
exit_code
|
222
|
+
ensure
|
223
|
+
write_th.terminate
|
224
|
+
in_rd.close
|
225
|
+
out_wr.close
|
226
|
+
err_wr.close
|
227
|
+
end
|
228
|
+
[in_wr, out_rd, err_rd, th]
|
229
|
+
rescue Errno::EMFILE => e
|
230
|
+
msg = "#{e.message}. This might be resolved by increasing your user limit "\
|
231
|
+
"with 'ulimit -n 1024'. See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details."
|
232
|
+
raise Bolt::Error.new(msg, 'bolt/too-many-files')
|
233
|
+
end
|
234
|
+
|
235
|
+
def upload_file(source, destination)
|
236
|
+
# Do not log wrapper script content
|
237
|
+
@logger.trace { "Uploading #{source} to #{destination}" } unless source.is_a?(StringIO)
|
238
|
+
@session.scp.upload!(source, destination, recursive: true)
|
239
|
+
rescue StandardError => e
|
240
|
+
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
241
|
+
end
|
242
|
+
|
243
|
+
def download_file(source, destination, _download)
|
244
|
+
# Do not log wrapper script content
|
245
|
+
@logger.trace { "Downloading #{source} to #{destination}" }
|
246
|
+
@session.scp.download!(source, destination, recursive: true)
|
247
|
+
rescue StandardError => e
|
248
|
+
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
249
|
+
end
|
250
|
+
|
251
|
+
# This handles renaming Net::SSH verifiers between version 4.x and 5.x
|
252
|
+
# of the gem
|
253
|
+
def net_ssh_verifier(verifier)
|
254
|
+
case verifier
|
255
|
+
when :always
|
256
|
+
if defined?(Net::SSH::Verifiers::Always)
|
257
|
+
Net::SSH::Verifiers::Always.new
|
258
|
+
else
|
259
|
+
Net::SSH::Verifiers::Secure.new
|
260
|
+
end
|
261
|
+
when :never
|
262
|
+
if defined?(Net::SSH::Verifiers::Never)
|
263
|
+
Net::SSH::Verifiers::Never.new
|
264
|
+
else
|
265
|
+
Net::SSH::Verifiers::Null.new
|
266
|
+
end
|
267
|
+
when :accept_new_or_tunnel_local
|
268
|
+
if defined?(Net::SSH::Verifiers::AcceptNewOrLocalTunnel)
|
269
|
+
Net::SSH::Verifiers::AcceptNewOrLocalTunnel.new
|
270
|
+
else
|
271
|
+
Net::SSH::Verifiers::Lenient.new
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# Add all default algorithms if the 'defaults' key is present and filter
|
277
|
+
# out any unsupported algorithms.
|
278
|
+
def net_ssh_algorithms(type, algorithms)
|
279
|
+
if algorithms.include?('defaults')
|
280
|
+
defaults = Net::SSH::Transport::Algorithms::DEFAULT_ALGORITHMS[type]
|
281
|
+
algorithms += defaults
|
282
|
+
end
|
283
|
+
|
284
|
+
known = Net::SSH::Transport::Algorithms::ALGORITHMS[type]
|
285
|
+
|
286
|
+
algorithms & known
|
287
|
+
end
|
288
|
+
|
289
|
+
def shell
|
290
|
+
@shell ||= if target.options['login-shell'] == 'powershell'
|
291
|
+
Bolt::Shell::Powershell.new(target, self)
|
292
|
+
else
|
293
|
+
Bolt::Shell::Bash.new(target, self)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# This is used by the Bash shell to decide whether to `cd` before
|
298
|
+
# executing commands as a run-as user
|
299
|
+
def reset_cwd?
|
300
|
+
true
|
301
|
+
end
|
302
|
+
|
303
|
+
def max_command_length
|
304
|
+
if target.options['login-shell'] == 'powershell'
|
305
|
+
32000
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def validate_ssh_version
|
310
|
+
remote_version = @session.transport.server_version.version
|
311
|
+
return unless target.options['login-shell'] && remote_version
|
312
|
+
|
313
|
+
match = remote_version.match(/OpenSSH_for_Windows_(\d+\.\d+)/)
|
314
|
+
if match && match[1].to_f < 7.9
|
315
|
+
raise "Powershell over SSH requires OpenSSH server >= 7.9, target is running #{match[1]}"
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
|
5
|
+
module Bolt
|
6
|
+
module Transport
|
7
|
+
class SSH < Simple
|
8
|
+
class ExecConnection
|
9
|
+
attr_reader :user, :target
|
10
|
+
|
11
|
+
def initialize(target)
|
12
|
+
raise Bolt::ValidationError, "Target #{target.safe_name} does not have a host" unless target.host
|
13
|
+
|
14
|
+
@target = target
|
15
|
+
begin
|
16
|
+
ssh_config = Net::SSH::Config.for(target.host)
|
17
|
+
@user = @target.user || ssh_config[:user] || Etc.getlogin
|
18
|
+
rescue StandardError
|
19
|
+
@user = @target.user || Etc.getlogin
|
20
|
+
end
|
21
|
+
@logger = Bolt::Logger.logger(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
# This is used to verify we can connect to targets with `connected?`
|
25
|
+
def connect
|
26
|
+
cmd = build_ssh_command('exit')
|
27
|
+
_, err, stat = Open3.capture3(*cmd)
|
28
|
+
unless stat.success?
|
29
|
+
raise Bolt::Node::ConnectError.new(
|
30
|
+
"Failed to connect to #{@target.safe_name}: #{err}",
|
31
|
+
'CONNECT_ERROR'
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def disconnect; end
|
37
|
+
|
38
|
+
def shell
|
39
|
+
Bolt::Shell::Bash.new(@target, self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def userhost
|
43
|
+
"#{@user}@#{@target.host}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def ssh_opts
|
47
|
+
# NOTE: not all commands we might use here support various `-o` options,
|
48
|
+
# always provide a way to run without them.
|
49
|
+
cmd = []
|
50
|
+
# BatchMode is SSH's noninteractive option: if key authentication
|
51
|
+
# fails it will error out instead of falling back to password prompt
|
52
|
+
cmd += %w[-o BatchMode=yes] if @target.transport_config['batch-mode']
|
53
|
+
|
54
|
+
cmd += %W[-o Port=#{@target.port}] if @target.port
|
55
|
+
|
56
|
+
if @target.transport_config.key?('host-key-check')
|
57
|
+
hkc = @target.transport_config['host-key-check'] ? 'yes' : 'no'
|
58
|
+
cmd += %W[-o StrictHostKeyChecking=#{hkc}]
|
59
|
+
end
|
60
|
+
|
61
|
+
if (key = target.transport_config['private-key'])
|
62
|
+
cmd += ['-i', key]
|
63
|
+
end
|
64
|
+
cmd
|
65
|
+
end
|
66
|
+
|
67
|
+
def build_ssh_command(command)
|
68
|
+
ssh_conf = @target.transport_config['ssh-command'] || 'ssh'
|
69
|
+
ssh_cmd = Array(ssh_conf)
|
70
|
+
ssh_cmd += ssh_opts
|
71
|
+
ssh_cmd << userhost
|
72
|
+
# Add option separator before command for wrappers around SSH
|
73
|
+
ssh_cmd << '--'
|
74
|
+
ssh_cmd << command
|
75
|
+
end
|
76
|
+
|
77
|
+
def upload_file(source, dest)
|
78
|
+
@logger.trace { "Uploading #{source} to #{dest}" } unless source.is_a?(StringIO)
|
79
|
+
|
80
|
+
cp_conf = @target.transport_config['copy-command'] || ["scp", "-r"]
|
81
|
+
cp_cmd = Array(cp_conf)
|
82
|
+
cp_cmd += ssh_opts
|
83
|
+
|
84
|
+
_, err, stat = if source.is_a?(StringIO)
|
85
|
+
Tempfile.create(File.basename(dest)) do |f|
|
86
|
+
f.write(source.read)
|
87
|
+
f.close
|
88
|
+
cp_cmd << f.path
|
89
|
+
cp_cmd << "#{userhost}:#{Shellwords.escape(dest)}"
|
90
|
+
Open3.capture3(*cp_cmd)
|
91
|
+
end
|
92
|
+
else
|
93
|
+
cp_cmd << source
|
94
|
+
cp_cmd << "#{userhost}:#{Shellwords.escape(dest)}"
|
95
|
+
Open3.capture3(*cp_cmd)
|
96
|
+
end
|
97
|
+
|
98
|
+
if stat.success?
|
99
|
+
@logger.trace "Successfully uploaded #{source} to #{dest}"
|
100
|
+
else
|
101
|
+
message = "Could not copy file to #{dest}: #{err}"
|
102
|
+
raise Bolt::Node::FileError.new(message, 'COPY_ERROR')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def download_file(source, dest, _download)
|
107
|
+
@logger.trace { "Downloading #{userhost}:#{source} to #{dest}" }
|
108
|
+
|
109
|
+
FileUtils.mkdir_p(dest)
|
110
|
+
|
111
|
+
cp_conf = @target.transport_config['copy-command'] || ["scp", "-r"]
|
112
|
+
cp_cmd = Array(cp_conf)
|
113
|
+
cp_cmd += ssh_opts
|
114
|
+
cp_cmd << "#{userhost}:#{Shellwords.escape(source)}"
|
115
|
+
cp_cmd << dest
|
116
|
+
|
117
|
+
_, err, stat = Open3.capture3(*cp_cmd)
|
118
|
+
|
119
|
+
if stat.success?
|
120
|
+
@logger.trace "Successfully downloaded #{userhost}:#{source} to #{dest}"
|
121
|
+
else
|
122
|
+
message = "Could not copy file to #{dest}: #{err}"
|
123
|
+
raise Bolt::Node::FileError.new(message, 'COPY_ERROR')
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def execute(command)
|
128
|
+
cmd_array = build_ssh_command(command)
|
129
|
+
Open3.popen3(*cmd_array)
|
130
|
+
end
|
131
|
+
|
132
|
+
# This is used by the Bash shell to decide whether to `cd` before
|
133
|
+
# executing commands as a run-as user
|
134
|
+
def reset_cwd?
|
135
|
+
true
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../bolt/logger'
|
4
|
+
require_relative '../../bolt/node/errors'
|
5
|
+
require_relative '../../bolt/transport/simple'
|
6
|
+
|
7
|
+
module Bolt
|
8
|
+
module Transport
|
9
|
+
class SSH < Simple
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
|
13
|
+
require 'net/ssh'
|
14
|
+
require 'net/scp'
|
15
|
+
begin
|
16
|
+
require 'net/ssh/krb'
|
17
|
+
rescue LoadError
|
18
|
+
logger.debug("Authentication method 'gssapi-with-mic' (Kerberos) is not available.")
|
19
|
+
end
|
20
|
+
@transport_logger = Bolt::Logger.logger(Net::SSH)
|
21
|
+
@transport_logger.level = :warn
|
22
|
+
end
|
23
|
+
|
24
|
+
def with_connection(target)
|
25
|
+
if target.transport_config['ssh-command'] && !target.transport_config['native-ssh']
|
26
|
+
Bolt::Logger.warn_once("native_ssh_disabled", "native-ssh must be true to use ssh-command")
|
27
|
+
end
|
28
|
+
|
29
|
+
conn = if target.transport_config['native-ssh']
|
30
|
+
ExecConnection.new(target)
|
31
|
+
else
|
32
|
+
Connection.new(target, @transport_logger)
|
33
|
+
end
|
34
|
+
conn.connect
|
35
|
+
yield conn
|
36
|
+
ensure
|
37
|
+
begin
|
38
|
+
conn&.disconnect
|
39
|
+
rescue StandardError => e
|
40
|
+
logger.info("Failed to close connection to #{target.safe_name} : #{e.message}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
require_relative 'ssh/connection'
|
48
|
+
require_relative 'ssh/exec_connection'
|