openbolt 5.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. checksums.yaml +7 -0
  2. data/Puppetfile +52 -0
  3. data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +60 -0
  4. data/bolt-modules/boltlib/lib/puppet/datatypes/containerresult.rb +51 -0
  5. data/bolt-modules/boltlib/lib/puppet/datatypes/future.rb +25 -0
  6. data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +71 -0
  7. data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +55 -0
  8. data/bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb +65 -0
  9. data/bolt-modules/boltlib/lib/puppet/datatypes/target.rb +93 -0
  10. data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +33 -0
  11. data/bolt-modules/boltlib/lib/puppet/functions/add_to_group.rb +38 -0
  12. data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +208 -0
  13. data/bolt-modules/boltlib/lib/puppet/functions/background.rb +62 -0
  14. data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +57 -0
  15. data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +130 -0
  16. data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +31 -0
  17. data/bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb +52 -0
  18. data/bolt-modules/boltlib/lib/puppet/functions/get_resources.rb +87 -0
  19. data/bolt-modules/boltlib/lib/puppet/functions/get_target.rb +34 -0
  20. data/bolt-modules/boltlib/lib/puppet/functions/get_targets.rb +35 -0
  21. data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +74 -0
  22. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_command.rb +97 -0
  23. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb +47 -0
  24. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +52 -0
  25. data/bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb +40 -0
  26. data/bolt-modules/boltlib/lib/puppet/functions/resolve_references.rb +42 -0
  27. data/bolt-modules/boltlib/lib/puppet/functions/resource.rb +53 -0
  28. data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +106 -0
  29. data/bolt-modules/boltlib/lib/puppet/functions/run_container.rb +162 -0
  30. data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +291 -0
  31. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +145 -0
  32. data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +164 -0
  33. data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +211 -0
  34. data/bolt-modules/boltlib/lib/puppet/functions/set_config.rb +48 -0
  35. data/bolt-modules/boltlib/lib/puppet/functions/set_feature.rb +43 -0
  36. data/bolt-modules/boltlib/lib/puppet/functions/set_resources.rb +145 -0
  37. data/bolt-modules/boltlib/lib/puppet/functions/set_var.rb +38 -0
  38. data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +101 -0
  39. data/bolt-modules/boltlib/lib/puppet/functions/vars.rb +29 -0
  40. data/bolt-modules/boltlib/lib/puppet/functions/wait.rb +131 -0
  41. data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +59 -0
  42. data/bolt-modules/boltlib/lib/puppet/functions/without_default_logging.rb +39 -0
  43. data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +50 -0
  44. data/bolt-modules/boltlib/types/planresult.pp +18 -0
  45. data/bolt-modules/boltlib/types/targetspec.pp +7 -0
  46. data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +42 -0
  47. data/bolt-modules/ctrl/lib/puppet/functions/ctrl/sleep.rb +20 -0
  48. data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +35 -0
  49. data/bolt-modules/file/lib/puppet/functions/file/delete.rb +21 -0
  50. data/bolt-modules/file/lib/puppet/functions/file/exists.rb +28 -0
  51. data/bolt-modules/file/lib/puppet/functions/file/join.rb +20 -0
  52. data/bolt-modules/file/lib/puppet/functions/file/read.rb +33 -0
  53. data/bolt-modules/file/lib/puppet/functions/file/readable.rb +28 -0
  54. data/bolt-modules/file/lib/puppet/functions/file/write.rb +24 -0
  55. data/bolt-modules/log/lib/puppet/functions/log/debug.rb +39 -0
  56. data/bolt-modules/log/lib/puppet/functions/log/error.rb +40 -0
  57. data/bolt-modules/log/lib/puppet/functions/log/fatal.rb +40 -0
  58. data/bolt-modules/log/lib/puppet/functions/log/info.rb +39 -0
  59. data/bolt-modules/log/lib/puppet/functions/log/trace.rb +39 -0
  60. data/bolt-modules/log/lib/puppet/functions/log/warn.rb +41 -0
  61. data/bolt-modules/out/lib/puppet/functions/out/message.rb +36 -0
  62. data/bolt-modules/out/lib/puppet/functions/out/verbose.rb +35 -0
  63. data/bolt-modules/prompt/lib/puppet/functions/prompt/menu.rb +103 -0
  64. data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +65 -0
  65. data/bolt-modules/system/lib/puppet/functions/system/env.rb +20 -0
  66. data/exe/bolt +17 -0
  67. data/guides/debugging.yaml +27 -0
  68. data/guides/inventory.yaml +23 -0
  69. data/guides/links.yaml +12 -0
  70. data/guides/logging.yaml +17 -0
  71. data/guides/module.yaml +18 -0
  72. data/guides/modulepath.yaml +24 -0
  73. data/guides/project.yaml +21 -0
  74. data/guides/targets.yaml +28 -0
  75. data/guides/transports.yaml +22 -0
  76. data/lib/bolt/analytics.rb +233 -0
  77. data/lib/bolt/application.rb +806 -0
  78. data/lib/bolt/applicator.rb +368 -0
  79. data/lib/bolt/apply_inventory.rb +93 -0
  80. data/lib/bolt/apply_result.rb +154 -0
  81. data/lib/bolt/apply_target.rb +90 -0
  82. data/lib/bolt/bolt_option_parser.rb +1226 -0
  83. data/lib/bolt/catalog/logging.rb +15 -0
  84. data/lib/bolt/catalog.rb +144 -0
  85. data/lib/bolt/cli.rb +949 -0
  86. data/lib/bolt/config/modulepath.rb +30 -0
  87. data/lib/bolt/config/options.rb +673 -0
  88. data/lib/bolt/config/transport/base.rb +133 -0
  89. data/lib/bolt/config/transport/docker.rb +34 -0
  90. data/lib/bolt/config/transport/jail.rb +33 -0
  91. data/lib/bolt/config/transport/local.rb +39 -0
  92. data/lib/bolt/config/transport/lxd.rb +34 -0
  93. data/lib/bolt/config/transport/options.rb +431 -0
  94. data/lib/bolt/config/transport/orch.rb +41 -0
  95. data/lib/bolt/config/transport/podman.rb +33 -0
  96. data/lib/bolt/config/transport/remote.rb +24 -0
  97. data/lib/bolt/config/transport/ssh.rb +138 -0
  98. data/lib/bolt/config/transport/winrm.rb +63 -0
  99. data/lib/bolt/config.rb +515 -0
  100. data/lib/bolt/container_result.rb +105 -0
  101. data/lib/bolt/error.rb +194 -0
  102. data/lib/bolt/executor.rb +539 -0
  103. data/lib/bolt/fiber_executor.rb +190 -0
  104. data/lib/bolt/inventory/group.rb +446 -0
  105. data/lib/bolt/inventory/inventory.rb +391 -0
  106. data/lib/bolt/inventory/options.rb +139 -0
  107. data/lib/bolt/inventory/target.rb +293 -0
  108. data/lib/bolt/inventory.rb +120 -0
  109. data/lib/bolt/logger.rb +252 -0
  110. data/lib/bolt/module.rb +54 -0
  111. data/lib/bolt/module_installer/installer.rb +44 -0
  112. data/lib/bolt/module_installer/puppetfile/forge_module.rb +54 -0
  113. data/lib/bolt/module_installer/puppetfile/git_module.rb +37 -0
  114. data/lib/bolt/module_installer/puppetfile/module.rb +26 -0
  115. data/lib/bolt/module_installer/puppetfile.rb +131 -0
  116. data/lib/bolt/module_installer/resolver.rb +129 -0
  117. data/lib/bolt/module_installer/specs/forge_spec.rb +91 -0
  118. data/lib/bolt/module_installer/specs/git_spec.rb +150 -0
  119. data/lib/bolt/module_installer/specs/id/base.rb +116 -0
  120. data/lib/bolt/module_installer/specs/id/gitclone.rb +120 -0
  121. data/lib/bolt/module_installer/specs/id/github.rb +90 -0
  122. data/lib/bolt/module_installer/specs/id/gitlab.rb +92 -0
  123. data/lib/bolt/module_installer/specs.rb +95 -0
  124. data/lib/bolt/module_installer.rb +208 -0
  125. data/lib/bolt/node/errors.rb +55 -0
  126. data/lib/bolt/node/output.rb +29 -0
  127. data/lib/bolt/outputter/human.rb +958 -0
  128. data/lib/bolt/outputter/json.rb +205 -0
  129. data/lib/bolt/outputter/logger.rb +76 -0
  130. data/lib/bolt/outputter/rainbow.rb +118 -0
  131. data/lib/bolt/outputter.rb +57 -0
  132. data/lib/bolt/pal/issues.rb +19 -0
  133. data/lib/bolt/pal/logging.rb +17 -0
  134. data/lib/bolt/pal/yaml_plan/evaluator.rb +83 -0
  135. data/lib/bolt/pal/yaml_plan/loader.rb +94 -0
  136. data/lib/bolt/pal/yaml_plan/parameter.rb +63 -0
  137. data/lib/bolt/pal/yaml_plan/step/command.rb +45 -0
  138. data/lib/bolt/pal/yaml_plan/step/download.rb +37 -0
  139. data/lib/bolt/pal/yaml_plan/step/eval.rb +42 -0
  140. data/lib/bolt/pal/yaml_plan/step/message.rb +31 -0
  141. data/lib/bolt/pal/yaml_plan/step/plan.rb +42 -0
  142. data/lib/bolt/pal/yaml_plan/step/resources.rb +170 -0
  143. data/lib/bolt/pal/yaml_plan/step/script.rb +62 -0
  144. data/lib/bolt/pal/yaml_plan/step/task.rb +42 -0
  145. data/lib/bolt/pal/yaml_plan/step/upload.rb +37 -0
  146. data/lib/bolt/pal/yaml_plan/step/verbose.rb +31 -0
  147. data/lib/bolt/pal/yaml_plan/step.rb +223 -0
  148. data/lib/bolt/pal/yaml_plan/transpiler.rb +90 -0
  149. data/lib/bolt/pal/yaml_plan.rb +172 -0
  150. data/lib/bolt/pal.rb +847 -0
  151. data/lib/bolt/plan_creator.rb +219 -0
  152. data/lib/bolt/plan_future.rb +86 -0
  153. data/lib/bolt/plan_result.rb +44 -0
  154. data/lib/bolt/plugin/cache.rb +76 -0
  155. data/lib/bolt/plugin/env_var.rb +54 -0
  156. data/lib/bolt/plugin/module.rb +276 -0
  157. data/lib/bolt/plugin/prompt.rb +36 -0
  158. data/lib/bolt/plugin/puppet_connect_data.rb +84 -0
  159. data/lib/bolt/plugin/puppetdb.rb +124 -0
  160. data/lib/bolt/plugin/task.rb +72 -0
  161. data/lib/bolt/plugin.rb +380 -0
  162. data/lib/bolt/project.rb +219 -0
  163. data/lib/bolt/project_manager/config_migrator.rb +113 -0
  164. data/lib/bolt/project_manager/inventory_migrator.rb +67 -0
  165. data/lib/bolt/project_manager/migrator.rb +39 -0
  166. data/lib/bolt/project_manager/module_migrator.rb +203 -0
  167. data/lib/bolt/project_manager.rb +221 -0
  168. data/lib/bolt/puppetdb/client.rb +153 -0
  169. data/lib/bolt/puppetdb/config.rb +176 -0
  170. data/lib/bolt/puppetdb/instance.rb +146 -0
  171. data/lib/bolt/puppetdb.rb +15 -0
  172. data/lib/bolt/r10k_log_proxy.rb +30 -0
  173. data/lib/bolt/rerun.rb +55 -0
  174. data/lib/bolt/resource_instance.rb +133 -0
  175. data/lib/bolt/result.rb +247 -0
  176. data/lib/bolt/result_set.rb +128 -0
  177. data/lib/bolt/shell/bash/tmpdir.rb +62 -0
  178. data/lib/bolt/shell/bash.rb +516 -0
  179. data/lib/bolt/shell/powershell/snippets.rb +181 -0
  180. data/lib/bolt/shell/powershell.rb +365 -0
  181. data/lib/bolt/shell.rb +105 -0
  182. data/lib/bolt/target.rb +174 -0
  183. data/lib/bolt/task/puppet_server.rb +27 -0
  184. data/lib/bolt/task/run.rb +55 -0
  185. data/lib/bolt/task.rb +163 -0
  186. data/lib/bolt/transport/base.rb +252 -0
  187. data/lib/bolt/transport/docker/connection.rb +150 -0
  188. data/lib/bolt/transport/docker.rb +23 -0
  189. data/lib/bolt/transport/jail/connection.rb +81 -0
  190. data/lib/bolt/transport/jail.rb +21 -0
  191. data/lib/bolt/transport/local/connection.rb +106 -0
  192. data/lib/bolt/transport/local.rb +20 -0
  193. data/lib/bolt/transport/lxd/connection.rb +115 -0
  194. data/lib/bolt/transport/lxd.rb +26 -0
  195. data/lib/bolt/transport/orch/connection.rb +111 -0
  196. data/lib/bolt/transport/orch.rb +271 -0
  197. data/lib/bolt/transport/podman/connection.rb +102 -0
  198. data/lib/bolt/transport/podman.rb +19 -0
  199. data/lib/bolt/transport/remote.rb +41 -0
  200. data/lib/bolt/transport/simple.rb +54 -0
  201. data/lib/bolt/transport/ssh/connection.rb +321 -0
  202. data/lib/bolt/transport/ssh/exec_connection.rb +140 -0
  203. data/lib/bolt/transport/ssh.rb +48 -0
  204. data/lib/bolt/transport/winrm/connection.rb +378 -0
  205. data/lib/bolt/transport/winrm.rb +33 -0
  206. data/lib/bolt/util/format.rb +68 -0
  207. data/lib/bolt/util/puppet_log_level.rb +21 -0
  208. data/lib/bolt/util.rb +465 -0
  209. data/lib/bolt/validator.rb +227 -0
  210. data/lib/bolt/version.rb +5 -0
  211. data/lib/bolt.rb +8 -0
  212. data/lib/bolt_server/acl.rb +39 -0
  213. data/lib/bolt_server/base_config.rb +112 -0
  214. data/lib/bolt_server/config.rb +64 -0
  215. data/lib/bolt_server/file_cache.rb +200 -0
  216. data/lib/bolt_server/request_error.rb +11 -0
  217. data/lib/bolt_server/schemas/action-check_node_connections.json +14 -0
  218. data/lib/bolt_server/schemas/action-run_command.json +12 -0
  219. data/lib/bolt_server/schemas/action-run_script.json +47 -0
  220. data/lib/bolt_server/schemas/action-run_task.json +20 -0
  221. data/lib/bolt_server/schemas/action-upload_file.json +47 -0
  222. data/lib/bolt_server/schemas/partials/target-any.json +10 -0
  223. data/lib/bolt_server/schemas/partials/target-ssh.json +88 -0
  224. data/lib/bolt_server/schemas/partials/target-winrm.json +67 -0
  225. data/lib/bolt_server/schemas/partials/task.json +94 -0
  226. data/lib/bolt_server/schemas/transport-ssh.json +25 -0
  227. data/lib/bolt_server/schemas/transport-winrm.json +19 -0
  228. data/lib/bolt_server/transport_app.rb +554 -0
  229. data/lib/bolt_spec/bolt_context.rb +226 -0
  230. data/lib/bolt_spec/plans/action_stubs/command_stub.rb +51 -0
  231. data/lib/bolt_spec/plans/action_stubs/download_stub.rb +66 -0
  232. data/lib/bolt_spec/plans/action_stubs/plan_stub.rb +55 -0
  233. data/lib/bolt_spec/plans/action_stubs/script_stub.rb +59 -0
  234. data/lib/bolt_spec/plans/action_stubs/task_stub.rb +57 -0
  235. data/lib/bolt_spec/plans/action_stubs/upload_stub.rb +65 -0
  236. data/lib/bolt_spec/plans/action_stubs.rb +196 -0
  237. data/lib/bolt_spec/plans/mock_executor.rb +361 -0
  238. data/lib/bolt_spec/plans/publish_stub.rb +49 -0
  239. data/lib/bolt_spec/plans.rb +190 -0
  240. data/lib/bolt_spec/run.rb +246 -0
  241. data/lib/logging_extensions/logging.rb +13 -0
  242. data/libexec/apply_catalog.rb +130 -0
  243. data/libexec/bolt_catalog +68 -0
  244. data/libexec/custom_facts.rb +63 -0
  245. data/libexec/query_resources.rb +75 -0
  246. data/modules/aggregate/lib/puppet/functions/aggregate/count.rb +21 -0
  247. data/modules/aggregate/lib/puppet/functions/aggregate/nodes.rb +22 -0
  248. data/modules/aggregate/lib/puppet/functions/aggregate/targets.rb +21 -0
  249. data/modules/aggregate/plans/count.pp +56 -0
  250. data/modules/aggregate/plans/targets.pp +56 -0
  251. data/modules/canary/lib/puppet/functions/canary/merge.rb +13 -0
  252. data/modules/canary/lib/puppet/functions/canary/random_split.rb +22 -0
  253. data/modules/canary/lib/puppet/functions/canary/skip.rb +25 -0
  254. data/modules/canary/plans/init.pp +100 -0
  255. data/modules/puppet_connect/plans/test_input_data.pp +94 -0
  256. data/modules/puppetdb_fact/plans/init.pp +20 -0
  257. data/resources/bolt_bash_completion.sh +214 -0
  258. metadata +735 -0
@@ -0,0 +1,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'