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,378 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../bolt/node/errors'
|
4
|
+
require_relative '../../../bolt/node/output'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
module Transport
|
8
|
+
class WinRM < Simple
|
9
|
+
class Connection
|
10
|
+
attr_reader :logger, :target
|
11
|
+
|
12
|
+
def initialize(target, transport_logger)
|
13
|
+
raise Bolt::ValidationError, "Target #{target.safe_name} does not have a host" unless target.host
|
14
|
+
@target = target
|
15
|
+
|
16
|
+
default_port = target.options['ssl'] ? HTTPS_PORT : HTTP_PORT
|
17
|
+
@port = @target.port || default_port
|
18
|
+
@user = @target.user
|
19
|
+
# Build set of extensions from extensions config as well as interpreters
|
20
|
+
|
21
|
+
@logger = Bolt::Logger.logger(@target.safe_name)
|
22
|
+
logger.trace("Initializing winrm connection to #{@target.safe_name}")
|
23
|
+
@transport_logger = transport_logger
|
24
|
+
end
|
25
|
+
|
26
|
+
HTTP_PORT = 5985
|
27
|
+
HTTPS_PORT = 5986
|
28
|
+
|
29
|
+
def connect
|
30
|
+
if target.options['ssl']
|
31
|
+
scheme = 'https'
|
32
|
+
transport = :ssl
|
33
|
+
else
|
34
|
+
scheme = 'http'
|
35
|
+
transport = :negotiate
|
36
|
+
end
|
37
|
+
|
38
|
+
transport = :kerberos if target.options['realm']
|
39
|
+
endpoint = "#{scheme}://#{target.host}:#{@port}/wsman"
|
40
|
+
cacert = target.options['cacert'] && target.options['ssl'] ? File.expand_path(target.options['cacert']) : nil
|
41
|
+
options = { endpoint: endpoint,
|
42
|
+
# https://github.com/WinRb/WinRM/issues/270
|
43
|
+
user: target.options['realm'] ? 'dummy' : @user,
|
44
|
+
password: target.options['realm'] ? 'dummy' : target.password,
|
45
|
+
retry_limit: 1,
|
46
|
+
transport: transport,
|
47
|
+
basic_auth_only: target.options['basic-auth-only'],
|
48
|
+
ca_trust_path: cacert,
|
49
|
+
realm: target.options['realm'],
|
50
|
+
no_ssl_peer_verification: !target.options['ssl-verify'] }
|
51
|
+
|
52
|
+
Timeout.timeout(target.options['connect-timeout']) do
|
53
|
+
@connection = ::WinRM::Connection.new(options)
|
54
|
+
@connection.logger = @transport_logger
|
55
|
+
|
56
|
+
@connection.shell(:powershell) do |session|
|
57
|
+
session.run('$PSVersionTable.PSVersion')
|
58
|
+
end
|
59
|
+
|
60
|
+
@logger.trace { "Opened connection" }
|
61
|
+
end
|
62
|
+
rescue Timeout::Error
|
63
|
+
# If we're using the default port with SSL, a timeout probably means the
|
64
|
+
# host doesn't support SSL.
|
65
|
+
if target.options['ssl'] && @port == HTTPS_PORT
|
66
|
+
the_problem = "\nVerify that required WinRM ports are open, " \
|
67
|
+
"or use --no-ssl if this host isn't configured to use SSL for WinRM."
|
68
|
+
end
|
69
|
+
raise Bolt::Node::ConnectError.new(
|
70
|
+
"Timeout after #{target.options['connect-timeout']} seconds connecting to #{endpoint}#{the_problem}",
|
71
|
+
'CONNECT_ERROR'
|
72
|
+
)
|
73
|
+
rescue ::WinRM::WinRMAuthorizationError
|
74
|
+
raise Bolt::Node::ConnectError.new(
|
75
|
+
"Authentication failed for #{endpoint}",
|
76
|
+
'AUTH_ERROR'
|
77
|
+
)
|
78
|
+
rescue OpenSSL::SSL::SSLError => e
|
79
|
+
# If we're using SSL with the default non-SSL port, mention that as a likely problem
|
80
|
+
if target.options['ssl'] && @port == HTTP_PORT
|
81
|
+
theres_your_problem = "\nAre you using SSL to connect to a non-SSL port?"
|
82
|
+
end
|
83
|
+
if target.options['ssl-verify'] && e.message.include?('certificate verify failed')
|
84
|
+
theres_your_problem = "\nIs the remote host using a self-signed SSL "\
|
85
|
+
"certificate? Use --no-ssl-verify to disable "\
|
86
|
+
"remote host SSL verification."
|
87
|
+
end
|
88
|
+
raise Bolt::Node::ConnectError.new(
|
89
|
+
"Failed to connect to #{endpoint}: #{e.message}#{theres_your_problem}",
|
90
|
+
"CONNECT_ERROR"
|
91
|
+
)
|
92
|
+
rescue StandardError => e
|
93
|
+
raise Bolt::Node::ConnectError.new(
|
94
|
+
"Failed to connect to #{endpoint}: #{e.message}",
|
95
|
+
'CONNECT_ERROR'
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
def disconnect
|
100
|
+
@client&.disconnect!
|
101
|
+
@logger.trace { "Closed connection" }
|
102
|
+
end
|
103
|
+
|
104
|
+
def execute(command)
|
105
|
+
@logger.trace { "Executing command: #{command}" }
|
106
|
+
|
107
|
+
inp = StringIO.new
|
108
|
+
# This transport doesn't accept stdin, so close the stream to ensure
|
109
|
+
# it will fail if the shell attempts to provide stdin
|
110
|
+
inp.close
|
111
|
+
|
112
|
+
out_rd, out_wr = IO.pipe('UTF-8')
|
113
|
+
err_rd, err_wr = IO.pipe('UTF-8')
|
114
|
+
th = Thread.new do
|
115
|
+
# By default, any exception raised in a thread will be reported to
|
116
|
+
# stderr as a stacktrace. Since we know these errors are going to
|
117
|
+
# propagate to the main thread via the shell, there's no chance
|
118
|
+
# they will be unhandled, so the default stack trace is unneeded.
|
119
|
+
Thread.current.report_on_exception = false
|
120
|
+
|
121
|
+
# Open a new shell instance for each command executed. PowerShell is
|
122
|
+
# unable to unload any DLLs loaded when running a PowerShell script
|
123
|
+
# or task from the same shell instance they were loaded in, which
|
124
|
+
# prevents Bolt from cleaning up the temp directory successfully.
|
125
|
+
# Using a new PowerShell instance avoids this limitation.
|
126
|
+
@connection.shell(:powershell) do |session|
|
127
|
+
result = session.run(command)
|
128
|
+
out_wr << result.stdout
|
129
|
+
err_wr << result.stderr
|
130
|
+
result.exitcode
|
131
|
+
end
|
132
|
+
ensure
|
133
|
+
# Close the streams to avoid the caller deadlocking
|
134
|
+
out_wr.close
|
135
|
+
err_wr.close
|
136
|
+
end
|
137
|
+
|
138
|
+
[inp, out_rd, err_rd, th]
|
139
|
+
rescue Errno::EMFILE => e
|
140
|
+
msg = "#{e.message}. This might be resolved by increasing your user limit "\
|
141
|
+
"with 'ulimit -n 1024'. See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details."
|
142
|
+
raise Bolt::Error.new(msg, 'bolt/too-many-files')
|
143
|
+
rescue StandardError
|
144
|
+
@logger.trace { "Command aborted" }
|
145
|
+
raise
|
146
|
+
end
|
147
|
+
|
148
|
+
def upload_file(source, destination)
|
149
|
+
@logger.trace { "Uploading #{source} to #{destination}" }
|
150
|
+
if target.options['file-protocol'] == 'smb'
|
151
|
+
upload_file_smb(source, destination)
|
152
|
+
else
|
153
|
+
upload_file_winrm(source, destination)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def upload_file_winrm(source, destination)
|
158
|
+
fs = ::WinRM::FS::FileManager.new(@connection)
|
159
|
+
fs.upload(source, destination)
|
160
|
+
rescue StandardError => e
|
161
|
+
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
162
|
+
end
|
163
|
+
|
164
|
+
def upload_file_smb(source, destination)
|
165
|
+
# lazy-load expensive gem code
|
166
|
+
require 'ruby_smb'
|
167
|
+
|
168
|
+
win_dest = destination.tr('/', '\\')
|
169
|
+
if (md = win_dest.match(/^([a-z]):\\(.*)/i))
|
170
|
+
# if drive, use admin share for that drive, so path is '\\host\C$'
|
171
|
+
path = "\\\\#{@target.host}\\#{md[1]}$"
|
172
|
+
dest = md[2]
|
173
|
+
elsif (md = win_dest.match(/^(\\\\[^\\]+\\[^\\]+)\\(.*)/))
|
174
|
+
# if unc, path is '\\host\share'
|
175
|
+
path = md[1]
|
176
|
+
dest = md[2]
|
177
|
+
else
|
178
|
+
raise ArgumentError, "Unknown destination '#{destination}'"
|
179
|
+
end
|
180
|
+
|
181
|
+
client = smb_client_login
|
182
|
+
tree = client.tree_connect(path)
|
183
|
+
begin
|
184
|
+
upload_file_smb_recursive(tree, source, dest)
|
185
|
+
ensure
|
186
|
+
tree.disconnect!
|
187
|
+
end
|
188
|
+
rescue ::RubySMB::Error::UnexpectedStatusCode => e
|
189
|
+
raise Bolt::Node::FileError.new("SMB Error: #{e.message}", 'WRITE_ERROR')
|
190
|
+
rescue StandardError => e
|
191
|
+
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
192
|
+
end
|
193
|
+
|
194
|
+
def download_file(source, destination, download)
|
195
|
+
@logger.trace { "Downloading #{source} to #{destination}" }
|
196
|
+
if target.options['file-protocol'] == 'smb'
|
197
|
+
download_file_smb(source, destination)
|
198
|
+
else
|
199
|
+
download_file_winrm(source, destination, download)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def download_file_winrm(source, destination, download)
|
204
|
+
# The winrm gem doesn't create the destination directory if it's missing,
|
205
|
+
# so create it here
|
206
|
+
FileUtils.mkdir_p(destination)
|
207
|
+
fs = ::WinRM::FS::FileManager.new(@connection)
|
208
|
+
# params: source, destination, chunksize, first
|
209
|
+
# first needs to be set to false, otherwise if the source is a directory it
|
210
|
+
# will be nested inside a directory with the same name
|
211
|
+
fs.download(source, download, 1024 * 1024, false)
|
212
|
+
rescue StandardError => e
|
213
|
+
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
214
|
+
end
|
215
|
+
|
216
|
+
def download_file_smb(source, destination)
|
217
|
+
# lazy-load expensive gem code
|
218
|
+
require 'ruby_smb'
|
219
|
+
|
220
|
+
win_source = source.tr('/', '\\')
|
221
|
+
if (md = win_source.match(/^([a-z]):\\(.*)/i))
|
222
|
+
# if drive, use admin share for that drive, so path is '\\host\C$'
|
223
|
+
path = "\\\\#{@target.host}\\#{md[1]}$"
|
224
|
+
src = md[2]
|
225
|
+
elsif (md = win_source.match(/^(\\\\[^\\]+\\[^\\]+)\\(.*)/))
|
226
|
+
# if unc, path is '\\host\share'
|
227
|
+
path = md[1]
|
228
|
+
src = md[2]
|
229
|
+
else
|
230
|
+
raise ArgumentError, "Unknown source '#{source}'"
|
231
|
+
end
|
232
|
+
|
233
|
+
client = smb_client_login
|
234
|
+
tree = client.tree_connect(path)
|
235
|
+
|
236
|
+
begin
|
237
|
+
# Make sure the root download directory for the target exists
|
238
|
+
FileUtils.mkdir_p(destination)
|
239
|
+
download_file_smb_recursive(tree, src, destination)
|
240
|
+
ensure
|
241
|
+
tree.disconnect!
|
242
|
+
end
|
243
|
+
rescue ::RubySMB::Error::UnexpectedStatusCode => e
|
244
|
+
raise Bolt::Node::FileError.new("SMB Error: #{e.message}", 'DOWNLOAD_ERROR')
|
245
|
+
rescue StandardError => e
|
246
|
+
raise Bolt::Node::FileError.new(e.message, 'DOWNLOAD_ERROR')
|
247
|
+
end
|
248
|
+
|
249
|
+
def shell
|
250
|
+
@shell ||= Bolt::Shell::Powershell.new(target, self)
|
251
|
+
end
|
252
|
+
|
253
|
+
def max_command_length
|
254
|
+
nil
|
255
|
+
end
|
256
|
+
|
257
|
+
private
|
258
|
+
|
259
|
+
def smb_client_login
|
260
|
+
return @client if @client
|
261
|
+
|
262
|
+
dispatcher = RubySMB::Dispatcher::Socket.new(smb_socket_connect)
|
263
|
+
@client = RubySMB::Client.new(dispatcher, smb1: false, smb2: true, username: @user, password: target.password)
|
264
|
+
status = @client.login
|
265
|
+
case status
|
266
|
+
when WindowsError::NTStatus::STATUS_SUCCESS
|
267
|
+
@logger.trace { "Connected to #{@client.dns_host_name}" }
|
268
|
+
when WindowsError::NTStatus::STATUS_LOGON_FAILURE
|
269
|
+
raise Bolt::Node::ConnectError.new(
|
270
|
+
"SMB authentication failed for #{target.safe_name}",
|
271
|
+
'AUTH_ERROR'
|
272
|
+
)
|
273
|
+
else
|
274
|
+
raise Bolt::Node::ConnectError.new(
|
275
|
+
"Failed to connect to #{target.safe_name} using SMB: #{status.description}",
|
276
|
+
'CONNECT_ERROR'
|
277
|
+
)
|
278
|
+
end
|
279
|
+
|
280
|
+
@client
|
281
|
+
end
|
282
|
+
|
283
|
+
SMB_PORT = 445
|
284
|
+
|
285
|
+
def smb_socket_connect
|
286
|
+
# It's lame that TCPSocket doesn't take a connect timeout
|
287
|
+
# Using Timeout.timeout is bad, but is done elsewhere...
|
288
|
+
Timeout.timeout(target.options['connect-timeout']) do
|
289
|
+
TCPSocket.new(target.host, target.options['smb-port'] || SMB_PORT)
|
290
|
+
end
|
291
|
+
rescue Errno::ECONNREFUSED => e
|
292
|
+
# handle this to prevent obscuring error message as SMB problem
|
293
|
+
raise Bolt::Node::ConnectError.new(
|
294
|
+
"Failed to connect to #{target.safe_name} using SMB: #{e.message}",
|
295
|
+
'CONNECT_ERROR'
|
296
|
+
)
|
297
|
+
rescue Timeout::Error
|
298
|
+
raise Bolt::Node::ConnectError.new(
|
299
|
+
"Timeout after #{target.options['connect-timeout']} seconds connecting to #{target.safe_name}",
|
300
|
+
'CONNECT_ERROR'
|
301
|
+
)
|
302
|
+
end
|
303
|
+
|
304
|
+
def upload_file_smb_recursive(tree, source, dest)
|
305
|
+
if Dir.exist?(source)
|
306
|
+
tree.open_directory(directory: dest, write: true, disposition: ::RubySMB::Dispositions::FILE_OPEN_IF)
|
307
|
+
|
308
|
+
Dir.children(source).each do |child|
|
309
|
+
child_dest = dest + '\\' + child
|
310
|
+
upload_file_smb_recursive(tree, File.join(source, child), child_dest)
|
311
|
+
end
|
312
|
+
return
|
313
|
+
end
|
314
|
+
|
315
|
+
file = tree.open_file(filename: dest, write: true, disposition: ::RubySMB::Dispositions::FILE_OVERWRITE_IF)
|
316
|
+
begin
|
317
|
+
# `file` doesn't derive from IO, so can't use IO.copy_stream
|
318
|
+
File.open(source, 'rb') do |f|
|
319
|
+
pos = 0
|
320
|
+
while (buf = f.read(8 * 1024 * 1024))
|
321
|
+
file.write(data: buf, offset: pos)
|
322
|
+
pos += buf.length
|
323
|
+
end
|
324
|
+
end
|
325
|
+
ensure
|
326
|
+
file.close
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def download_file_smb_recursive(tree, source, destination)
|
331
|
+
dest = File.expand_path(Bolt::Util.windows_basename(source), destination)
|
332
|
+
|
333
|
+
# Check if the source is a directory by attempting to list its children.
|
334
|
+
# If the source is a directory, create the directory on the host and then
|
335
|
+
# recurse through the children.
|
336
|
+
if (children = list_directory_children_smb(tree, source))
|
337
|
+
FileUtils.mkdir_p(dest)
|
338
|
+
|
339
|
+
children.each do |child|
|
340
|
+
# File names are encoded UTF_16LE.
|
341
|
+
filename = child.file_name.encode(Encoding::UTF_8)
|
342
|
+
|
343
|
+
next if %w[. ..].include?(filename)
|
344
|
+
|
345
|
+
src = source + '\\' + filename
|
346
|
+
download_file_smb_recursive(tree, src, dest)
|
347
|
+
end
|
348
|
+
# If the source wasn't a directory and just returns 'STATUS_NOT_A_DIRECTORY, then
|
349
|
+
# it is a file. Write it to the host.
|
350
|
+
else
|
351
|
+
begin
|
352
|
+
file = tree.open_file(filename: source)
|
353
|
+
data = file.read
|
354
|
+
|
355
|
+
# Files may be encoded UTF_16LE
|
356
|
+
data = data.encode(Encoding::UTF_8) if data.encoding == Encoding::UTF_16LE
|
357
|
+
|
358
|
+
File.write(dest, data)
|
359
|
+
ensure
|
360
|
+
file.close
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
# Lists the children of a directory using rb_smb
|
366
|
+
# Returns an array of RubySMB::Fscc::FileInformation::FileIdFullDirectoryInformation objects
|
367
|
+
# if the source is a directory, or raises RubySMB::Error::UnexpectedStatusCode otherwise.
|
368
|
+
def list_directory_children_smb(tree, source)
|
369
|
+
tree.list(directory: source)
|
370
|
+
rescue RubySMB::Error::UnexpectedStatusCode => e
|
371
|
+
unless e.message == 'STATUS_NOT_A_DIRECTORY'
|
372
|
+
raise e
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../bolt/node/errors'
|
4
|
+
require_relative '../../bolt/transport/base'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
module Transport
|
8
|
+
class WinRM < Simple
|
9
|
+
def initialize
|
10
|
+
super
|
11
|
+
require 'winrm'
|
12
|
+
require 'winrm-fs'
|
13
|
+
|
14
|
+
@transport_logger = Bolt::Logger.logger(::WinRM)
|
15
|
+
@transport_logger.level = :warn
|
16
|
+
end
|
17
|
+
|
18
|
+
def with_connection(target)
|
19
|
+
conn = Connection.new(target, @transport_logger)
|
20
|
+
conn.connect
|
21
|
+
yield conn
|
22
|
+
ensure
|
23
|
+
begin
|
24
|
+
conn&.disconnect
|
25
|
+
rescue StandardError => e
|
26
|
+
logger.info("Failed to close connection to #{target.safe_name} : #{e.message}")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
require_relative 'winrm/connection'
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
module Util
|
5
|
+
module Format
|
6
|
+
class << self
|
7
|
+
# Stringifies an object, formatted as valid JSON.
|
8
|
+
#
|
9
|
+
# @param message [Object] The object to stringify.
|
10
|
+
# @return [String] The JSON string.
|
11
|
+
#
|
12
|
+
def stringify(message)
|
13
|
+
formatted = format_message(message)
|
14
|
+
if formatted.is_a?(Hash) || formatted.is_a?(Array)
|
15
|
+
::JSON.pretty_generate(formatted)
|
16
|
+
else
|
17
|
+
formatted
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Recursively formats an object into a format that can be represented by
|
22
|
+
# JSON.
|
23
|
+
#
|
24
|
+
# @param message [Object] The object to stringify.
|
25
|
+
# @return [Array, Hash, String]
|
26
|
+
#
|
27
|
+
private def format_message(message)
|
28
|
+
case message
|
29
|
+
when Array
|
30
|
+
message.map { |item| format_message(item) }
|
31
|
+
when Bolt::ApplyResult
|
32
|
+
format_apply_result(message)
|
33
|
+
when Bolt::Result, Bolt::ResultSet
|
34
|
+
# This is equivalent to to_s, but formattable
|
35
|
+
message.to_data
|
36
|
+
when Bolt::RunFailure
|
37
|
+
formatted_resultset = message.result_set.to_data
|
38
|
+
message.to_h.merge('result_set' => formatted_resultset)
|
39
|
+
when Hash
|
40
|
+
message.each_with_object({}) do |(k, v), h|
|
41
|
+
h[format_message(k)] = format_message(v)
|
42
|
+
end
|
43
|
+
when Integer, Float, NilClass
|
44
|
+
message
|
45
|
+
else
|
46
|
+
message.to_s
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Formats a Bolt::ApplyResult object.
|
51
|
+
#
|
52
|
+
# @param result [Bolt::ApplyResult] The apply result.
|
53
|
+
# @return [Hash]
|
54
|
+
#
|
55
|
+
private def format_apply_result(result)
|
56
|
+
logs = result.resource_logs&.map do |log|
|
57
|
+
# Omit low-level info/debug messages
|
58
|
+
next if %w[info debug].include?(log['level'])
|
59
|
+
indent(2, format_log(log))
|
60
|
+
end
|
61
|
+
hash = result.to_data
|
62
|
+
hash['logs'] = logs unless logs.empty?
|
63
|
+
hash
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
module Util
|
5
|
+
module PuppetLogLevel
|
6
|
+
MAPPING = {
|
7
|
+
# Demote Puppet's logs by one level, since Puppet is an implementation detail of Bolt
|
8
|
+
debug: :trace,
|
9
|
+
info: :debug,
|
10
|
+
notice: :info,
|
11
|
+
warning: :warn,
|
12
|
+
err: :error,
|
13
|
+
# The following are used by Puppet functions of the same name, and are all treated as
|
14
|
+
# error types in the Windows EventLog and log colors.
|
15
|
+
alert: :error,
|
16
|
+
emerg: :fatal,
|
17
|
+
crit: :fatal
|
18
|
+
}.freeze
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|