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,516 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'bash/tmpdir'
|
4
|
+
require 'shellwords'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
class Shell
|
8
|
+
class Bash < Shell
|
9
|
+
CHUNK_SIZE = 4096
|
10
|
+
|
11
|
+
def initialize(target, conn)
|
12
|
+
super
|
13
|
+
|
14
|
+
@run_as = nil
|
15
|
+
@sudo_id = SecureRandom.uuid
|
16
|
+
@sudo_password = @target.options['sudo-password'] || @target.password
|
17
|
+
end
|
18
|
+
|
19
|
+
def provided_features
|
20
|
+
['shell']
|
21
|
+
end
|
22
|
+
|
23
|
+
def run_command(command, options = {}, position = [])
|
24
|
+
running_as(options[:run_as]) do
|
25
|
+
output = execute(command, environment: options[:env_vars], sudoable: true)
|
26
|
+
Bolt::Result.for_command(target,
|
27
|
+
output.to_h,
|
28
|
+
'command',
|
29
|
+
command,
|
30
|
+
position)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def upload(source, destination, options = {})
|
35
|
+
running_as(options[:run_as]) do
|
36
|
+
with_tmpdir do |dir|
|
37
|
+
basename = File.basename(source)
|
38
|
+
tmpfile = File.join(dir.to_s, basename)
|
39
|
+
conn.upload_file(source, tmpfile)
|
40
|
+
# pass over file ownership if we're using run-as to be a different user
|
41
|
+
dir.chown(run_as)
|
42
|
+
result = execute(['mv', '-f', tmpfile, destination], sudoable: true)
|
43
|
+
if result.exit_code != 0
|
44
|
+
message = "Could not move temporary file '#{tmpfile}' to #{destination}: #{result.stderr.string}"
|
45
|
+
raise Bolt::Node::FileError.new(message, 'MV_ERROR')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
Bolt::Result.for_upload(target, source, destination)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def download(source, destination, options = {})
|
53
|
+
running_as(options[:run_as]) do
|
54
|
+
download = File.join(destination, Bolt::Util.unix_basename(source))
|
55
|
+
|
56
|
+
# If using run-as, the file is copied to a tmpdir and chowned to the
|
57
|
+
# connecting user. This is a workaround for limitations in net-ssh that
|
58
|
+
# only allow for downloading files as the connecting user, which is a
|
59
|
+
# problem for users who cannot connect to targets as the root user.
|
60
|
+
# This temporary copy should *always* be deleted.
|
61
|
+
if run_as
|
62
|
+
with_tmpdir(force_cleanup: true) do |dir|
|
63
|
+
tmpfile = File.join(dir.to_s, Bolt::Util.unix_basename(source))
|
64
|
+
|
65
|
+
result = execute(['cp', '-r', source, dir.to_s], sudoable: true)
|
66
|
+
|
67
|
+
if result.exit_code != 0
|
68
|
+
message = "Could not copy file '#{source}' to temporary directory '#{dir}': #{result.stderr.string}"
|
69
|
+
raise Bolt::Node::FileError.new(message, 'CP_ERROR')
|
70
|
+
end
|
71
|
+
|
72
|
+
# We need to force the chown, otherwise this will just return
|
73
|
+
# without doing anything since the chown user is the same as the
|
74
|
+
# connecting user.
|
75
|
+
dir.chown(conn.user, force: true)
|
76
|
+
|
77
|
+
conn.download_file(tmpfile, destination, download)
|
78
|
+
end
|
79
|
+
# If not using run-as, we can skip creating a temporary copy and just
|
80
|
+
# download the file directly.
|
81
|
+
else
|
82
|
+
conn.download_file(source, destination, download)
|
83
|
+
end
|
84
|
+
|
85
|
+
Bolt::Result.for_download(target, source, destination, download)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def run_script(script, arguments, options = {}, position = [])
|
90
|
+
# unpack any Sensitive data
|
91
|
+
arguments = unwrap_sensitive_args(arguments)
|
92
|
+
|
93
|
+
running_as(options[:run_as]) do
|
94
|
+
with_tmpdir do |dir|
|
95
|
+
path = write_executable(dir.to_s, script)
|
96
|
+
dir.chown(run_as)
|
97
|
+
|
98
|
+
exec_args = [path, *arguments]
|
99
|
+
interpreter = select_interpreter(script, target.options['interpreters'])
|
100
|
+
|
101
|
+
# Only use interpreter if script_interpreter config is enabled
|
102
|
+
if options[:script_interpreter] && interpreter
|
103
|
+
exec_args.unshift(interpreter).flatten!
|
104
|
+
logger.trace("Running '#{script}' using '#{interpreter}' interpreter")
|
105
|
+
end
|
106
|
+
|
107
|
+
output = execute(exec_args, environment: options[:env_vars], sudoable: true)
|
108
|
+
Bolt::Result.for_command(target,
|
109
|
+
output.to_h,
|
110
|
+
'script',
|
111
|
+
script,
|
112
|
+
position)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def run_task(task, arguments, options = {}, position = [])
|
118
|
+
implementation = select_implementation(target, task)
|
119
|
+
executable = implementation['path']
|
120
|
+
input_method = implementation['input_method']
|
121
|
+
extra_files = implementation['files']
|
122
|
+
|
123
|
+
running_as(options[:run_as]) do
|
124
|
+
stdin, output = nil
|
125
|
+
execute_options = {}
|
126
|
+
execute_options[:interpreter] = select_interpreter(executable, target.options['interpreters'])
|
127
|
+
interpreter_debug = if execute_options[:interpreter]
|
128
|
+
" using '#{execute_options[:interpreter]}' interpreter"
|
129
|
+
end
|
130
|
+
# log the arguments with sensitive data redacted, do NOT log unwrapped_arguments
|
131
|
+
logger.trace("Running '#{executable}' with #{arguments.to_json}#{interpreter_debug}")
|
132
|
+
# unpack any Sensitive data
|
133
|
+
arguments = unwrap_sensitive_args(arguments)
|
134
|
+
|
135
|
+
with_tmpdir do |dir|
|
136
|
+
if extra_files.empty?
|
137
|
+
task_dir = dir
|
138
|
+
else
|
139
|
+
# TODO: optimize upload of directories
|
140
|
+
arguments['_installdir'] = dir.to_s
|
141
|
+
task_dir = File.join(dir.to_s, task.tasks_dir)
|
142
|
+
dir.mkdirs([task.tasks_dir] + extra_files.map { |file| File.dirname(file['name']) })
|
143
|
+
extra_files.each do |file|
|
144
|
+
conn.upload_file(file['path'], File.join(dir.to_s, file['name']))
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
if Bolt::Task::STDIN_METHODS.include?(input_method)
|
149
|
+
stdin = JSON.dump(arguments)
|
150
|
+
end
|
151
|
+
|
152
|
+
if Bolt::Task::ENVIRONMENT_METHODS.include?(input_method)
|
153
|
+
execute_options[:environment] = envify_params(arguments)
|
154
|
+
end
|
155
|
+
|
156
|
+
remote_task_path = write_executable(task_dir, executable)
|
157
|
+
|
158
|
+
execute_options[:stdin] = stdin
|
159
|
+
|
160
|
+
# Avoid the horrors of passing data on stdin via a tty on multiple platforms
|
161
|
+
# by writing a wrapper script that directs stdin to the task.
|
162
|
+
if stdin && target.options['tty']
|
163
|
+
wrapper = make_wrapper_stringio(remote_task_path, stdin, execute_options[:interpreter])
|
164
|
+
# Wrapper script handles interpreter and stdin. Delete these execute options
|
165
|
+
execute_options.delete(:interpreter)
|
166
|
+
execute_options.delete(:stdin)
|
167
|
+
execute_options[:wrapper] = true
|
168
|
+
remote_task_path = write_executable(dir, wrapper, 'wrapper.sh')
|
169
|
+
end
|
170
|
+
|
171
|
+
dir.chown(run_as)
|
172
|
+
|
173
|
+
execute_options[:sudoable] = true if run_as
|
174
|
+
output = execute(remote_task_path, **execute_options)
|
175
|
+
end
|
176
|
+
Bolt::Result.for_task(target, output.stdout.string,
|
177
|
+
output.stderr.string,
|
178
|
+
output.exit_code,
|
179
|
+
task.name,
|
180
|
+
position)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# If prompted for sudo password, send password to stdin and return an
|
185
|
+
# empty string. Otherwise, check for sudo errors and raise Bolt error.
|
186
|
+
# If sudo_id is detected, that means the task needs to have stdin written.
|
187
|
+
# If error is not sudo-related, return the stderr string to be added to
|
188
|
+
# node output
|
189
|
+
def handle_sudo(stdin, err, sudo_stdin)
|
190
|
+
if err.include?(sudo_prompt)
|
191
|
+
# A wild sudo prompt has appeared!
|
192
|
+
if @sudo_password
|
193
|
+
stdin.write("#{@sudo_password}\n")
|
194
|
+
''
|
195
|
+
else
|
196
|
+
raise Bolt::Node::EscalateError.new(
|
197
|
+
"Sudo password for user #{conn.user} was not provided for #{target}",
|
198
|
+
'NO_PASSWORD'
|
199
|
+
)
|
200
|
+
end
|
201
|
+
elsif err =~ /^#{@sudo_id}/
|
202
|
+
if sudo_stdin
|
203
|
+
begin
|
204
|
+
stdin.write("#{sudo_stdin}\n")
|
205
|
+
stdin.close
|
206
|
+
# If a task has stdin as an input_method but doesn't actually read
|
207
|
+
# from stdin, the task may return and close the input stream before
|
208
|
+
# we finish writing
|
209
|
+
rescue Errno::EPIPE
|
210
|
+
end
|
211
|
+
end
|
212
|
+
''
|
213
|
+
else
|
214
|
+
handle_sudo_errors(err)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# See if there's a sudo prompt in the output
|
219
|
+
# If not, return the output
|
220
|
+
def check_sudo(out, inp, stdin)
|
221
|
+
buffer = out.readpartial(CHUNK_SIZE)
|
222
|
+
# Split on newlines, including the newline
|
223
|
+
lines = buffer.split(/(?<=\n)/)
|
224
|
+
# handle_sudo will return the line if it is not a sudo prompt or error
|
225
|
+
lines.map! { |line| handle_sudo(inp, line, stdin) }
|
226
|
+
lines.join
|
227
|
+
# If stream has reached EOF, no password prompt is expected
|
228
|
+
# return an empty string
|
229
|
+
rescue EOFError
|
230
|
+
''
|
231
|
+
end
|
232
|
+
|
233
|
+
def handle_sudo_errors(err)
|
234
|
+
case err
|
235
|
+
when /^#{conn.user} is not in the sudoers file\./
|
236
|
+
@logger.trace { err }
|
237
|
+
raise Bolt::Node::EscalateError.new(
|
238
|
+
"User #{conn.user} does not have sudo permission on #{target}",
|
239
|
+
'SUDO_DENIED'
|
240
|
+
)
|
241
|
+
when /^Sorry, try again\./
|
242
|
+
@logger.trace { err }
|
243
|
+
raise Bolt::Node::EscalateError.new(
|
244
|
+
"Sudo password for user #{conn.user} not recognized on #{target}",
|
245
|
+
'BAD_PASSWORD'
|
246
|
+
)
|
247
|
+
else
|
248
|
+
# No need to raise an error - just return the string
|
249
|
+
err
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def make_wrapper_stringio(task_path, stdin, interpreter = nil)
|
254
|
+
if interpreter
|
255
|
+
StringIO.new(<<~SCRIPT)
|
256
|
+
#!/bin/sh
|
257
|
+
#{Array(interpreter).map { |word| "'#{word}'" }.join(' ')} '#{task_path}' <<'EOF'
|
258
|
+
#{stdin}
|
259
|
+
EOF
|
260
|
+
SCRIPT
|
261
|
+
else
|
262
|
+
StringIO.new(<<~SCRIPT)
|
263
|
+
#!/bin/sh
|
264
|
+
'#{task_path}' <<'EOF'
|
265
|
+
#{stdin}
|
266
|
+
EOF
|
267
|
+
SCRIPT
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# This method allows the @run_as variable to be used as a per-operation
|
272
|
+
# override for the user to run as. When @run_as is unset, the user
|
273
|
+
# specified on the target will be used.
|
274
|
+
def run_as
|
275
|
+
@run_as || target.options['run-as']
|
276
|
+
end
|
277
|
+
|
278
|
+
# Run as the specified user for the duration of the block.
|
279
|
+
def running_as(user)
|
280
|
+
@run_as = user
|
281
|
+
yield
|
282
|
+
ensure
|
283
|
+
@run_as = nil
|
284
|
+
end
|
285
|
+
|
286
|
+
def make_executable(path)
|
287
|
+
result = execute(['chmod', 'u+x', path])
|
288
|
+
if result.exit_code != 0
|
289
|
+
message = "Could not make file '#{path}' executable: #{result.stderr.string}"
|
290
|
+
raise Bolt::Node::FileError.new(message, 'CHMOD_ERROR')
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def make_tmpdir
|
295
|
+
tmpdir = @target.options.fetch('tmpdir', '/tmp')
|
296
|
+
script_dir = @target.options.fetch('script-dir', SecureRandom.uuid)
|
297
|
+
tmppath = File.join(tmpdir, script_dir)
|
298
|
+
command = ['mkdir', '-m', 700, tmppath]
|
299
|
+
|
300
|
+
result = execute(command)
|
301
|
+
if result.exit_code != 0
|
302
|
+
raise Bolt::Node::FileError.new("Could not make tmpdir: #{result.stderr.string}", 'TMPDIR_ERROR')
|
303
|
+
end
|
304
|
+
path = tmppath || result.stdout.string.chomp
|
305
|
+
Bolt::Shell::Bash::Tmpdir.new(self, path)
|
306
|
+
end
|
307
|
+
|
308
|
+
def write_executable(dir, file, filename = nil)
|
309
|
+
filename ||= File.basename(file)
|
310
|
+
remote_path = File.join(dir.to_s, filename)
|
311
|
+
conn.upload_file(file, remote_path)
|
312
|
+
make_executable(remote_path)
|
313
|
+
remote_path
|
314
|
+
end
|
315
|
+
|
316
|
+
# A helper to create and delete a tmpdir on the remote system. Yields the
|
317
|
+
# directory name.
|
318
|
+
def with_tmpdir(force_cleanup: false)
|
319
|
+
dir = make_tmpdir
|
320
|
+
yield dir
|
321
|
+
ensure
|
322
|
+
if dir
|
323
|
+
if target.options['cleanup'] || force_cleanup
|
324
|
+
dir.delete
|
325
|
+
else
|
326
|
+
Bolt::Logger.warn("skip_cleanup", "Skipping cleanup of tmpdir #{dir}")
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def sudo_success(sudo_id)
|
332
|
+
"echo #{sudo_id} 1>&2"
|
333
|
+
end
|
334
|
+
|
335
|
+
# Returns string with the interpreter conditionally prepended
|
336
|
+
def inject_interpreter(interpreter, command)
|
337
|
+
if interpreter
|
338
|
+
command = Array(command).unshift(interpreter).flatten
|
339
|
+
end
|
340
|
+
|
341
|
+
command.is_a?(String) ? command : Shellwords.shelljoin(command)
|
342
|
+
end
|
343
|
+
|
344
|
+
def execute(command, sudoable: false, **options)
|
345
|
+
run_as = options[:run_as] || self.run_as
|
346
|
+
escalate = sudoable && run_as && conn.user != run_as
|
347
|
+
use_sudo = escalate && @target.options['run-as-command'].nil?
|
348
|
+
|
349
|
+
# Depending on the transport, whether we're using sudo and whether
|
350
|
+
# there are environment variables to set, we may need to stitch
|
351
|
+
# together multiple commands into a single sh invocation
|
352
|
+
commands = [inject_interpreter(options[:interpreter], command)]
|
353
|
+
|
354
|
+
# Let the transport handle adding environment variables if it's custom.
|
355
|
+
if options[:environment]
|
356
|
+
if defined? conn.add_env_vars
|
357
|
+
conn.add_env_vars(options[:environment])
|
358
|
+
else
|
359
|
+
env_decl = '/usr/bin/env ' + options[:environment].map do |env, val|
|
360
|
+
"#{env}=#{Shellwords.shellescape(val)}"
|
361
|
+
end.join(' ')
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
if escalate
|
366
|
+
sudo_str = if use_sudo
|
367
|
+
sudo_exec = target.options['sudo-executable'] || "sudo"
|
368
|
+
sudo_flags = [sudo_exec, "-S", "-H", "-u", run_as, "-p", sudo_prompt]
|
369
|
+
Shellwords.shelljoin(sudo_flags)
|
370
|
+
else
|
371
|
+
Shellwords.shelljoin(@target.options['run-as-command'] + [run_as])
|
372
|
+
end
|
373
|
+
commands.unshift('cd') if conn.reset_cwd?
|
374
|
+
commands.unshift(sudo_success(@sudo_id)) if options[:stdin] && !options[:wrapper]
|
375
|
+
end
|
376
|
+
|
377
|
+
command_str = if sudo_str || env_decl
|
378
|
+
"sh -c #{Shellwords.shellescape(commands.join('; '))}"
|
379
|
+
else
|
380
|
+
commands.last
|
381
|
+
end
|
382
|
+
|
383
|
+
command_str = [sudo_str, env_decl, command_str].compact.join(' ')
|
384
|
+
|
385
|
+
@logger.trace { "Executing `#{command_str}`" }
|
386
|
+
|
387
|
+
in_buffer = if !use_sudo && options[:stdin]
|
388
|
+
String.new(options[:stdin], encoding: 'binary')
|
389
|
+
else
|
390
|
+
String.new(encoding: 'binary')
|
391
|
+
end
|
392
|
+
# Chunks of this size will be read in one iteration
|
393
|
+
index = 0
|
394
|
+
timeout = 0.1
|
395
|
+
result_output = Bolt::Node::Output.new
|
396
|
+
|
397
|
+
inp, out, err, t = conn.execute(command_str)
|
398
|
+
read_streams = { out => String.new,
|
399
|
+
err => String.new }
|
400
|
+
write_stream = in_buffer.empty? ? [] : [inp]
|
401
|
+
|
402
|
+
# See if there's a sudo prompt
|
403
|
+
if use_sudo
|
404
|
+
ready_read = select([err], nil, nil, timeout * 5)
|
405
|
+
to_print = check_sudo(err, inp, options[:stdin]) if ready_read
|
406
|
+
unless to_print.nil?
|
407
|
+
log_stream(to_print, 'err')
|
408
|
+
read_streams[err] << to_print
|
409
|
+
result_output.merged_output << to_print
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
# True while the process is running or waiting for IO input
|
414
|
+
while t.alive?
|
415
|
+
# See if we can read from out or err, or write to in
|
416
|
+
ready_read, ready_write, = select(read_streams.keys, write_stream, nil, timeout)
|
417
|
+
|
418
|
+
ready_read&.each do |stream|
|
419
|
+
stream_name = stream == out ? 'out' : 'err'
|
420
|
+
# Check for sudo prompt
|
421
|
+
to_print = if use_sudo
|
422
|
+
check_sudo(stream, inp, options[:stdin])
|
423
|
+
else
|
424
|
+
stream.readpartial(CHUNK_SIZE)
|
425
|
+
end
|
426
|
+
log_stream(to_print, stream_name)
|
427
|
+
read_streams[stream] << to_print
|
428
|
+
result_output.merged_output << to_print
|
429
|
+
rescue EOFError
|
430
|
+
end
|
431
|
+
|
432
|
+
# select will either return an empty array if there are no
|
433
|
+
# writable streams or nil if no IO object is available before the
|
434
|
+
# timeout is reached.
|
435
|
+
writable = if ready_write.respond_to?(:empty?)
|
436
|
+
!ready_write.empty?
|
437
|
+
else
|
438
|
+
!ready_write.nil?
|
439
|
+
end
|
440
|
+
|
441
|
+
begin
|
442
|
+
if writable && index < in_buffer.length
|
443
|
+
to_print = in_buffer[index..-1]
|
444
|
+
# On Windows, select marks the input stream as writable even if
|
445
|
+
# it's full. We need to check whether we received wait_writable
|
446
|
+
# and treat that as not having written anything.
|
447
|
+
written = inp.write_nonblock(to_print, exception: false)
|
448
|
+
index += written unless written == :wait_writable
|
449
|
+
|
450
|
+
if index >= in_buffer.length && !write_stream.empty?
|
451
|
+
inp.close
|
452
|
+
write_stream = []
|
453
|
+
end
|
454
|
+
end
|
455
|
+
# If a task has stdin as an input_method but doesn't actually read
|
456
|
+
# from stdin, the task may return and close the input stream before
|
457
|
+
# we finish writing
|
458
|
+
rescue Errno::EPIPE
|
459
|
+
write_stream = []
|
460
|
+
end
|
461
|
+
end
|
462
|
+
# Read any remaining data in the pipe. Do not wait for
|
463
|
+
# EOF in case the pipe is inherited by a child process.
|
464
|
+
read_streams.each do |stream, _|
|
465
|
+
stream_name = stream == out ? 'out' : 'err'
|
466
|
+
loop {
|
467
|
+
to_print = stream.read_nonblock(CHUNK_SIZE)
|
468
|
+
log_stream(to_print, stream_name)
|
469
|
+
read_streams[stream] << to_print
|
470
|
+
result_output.merged_output << to_print
|
471
|
+
}
|
472
|
+
rescue Errno::EAGAIN, EOFError
|
473
|
+
ensure
|
474
|
+
stream.close
|
475
|
+
end
|
476
|
+
inp.close
|
477
|
+
result_output.stdout << read_streams[out]
|
478
|
+
result_output.stderr << read_streams[err]
|
479
|
+
result_output.exit_code = t.value.respond_to?(:exitstatus) ? t.value.exitstatus : t.value
|
480
|
+
|
481
|
+
case result_output.exit_code
|
482
|
+
when 0
|
483
|
+
@logger.trace { "Command `#{command_str}` returned successfully" }
|
484
|
+
when 126
|
485
|
+
msg = "\n\nThis might be caused by the default tmpdir being mounted "\
|
486
|
+
"using 'noexec'. See http://pup.pt/task-failure for details and workarounds."
|
487
|
+
result_output.stderr << msg
|
488
|
+
result_output.merged_output << msg
|
489
|
+
@logger.trace { "Command #{command_str} failed with exit code #{result_output.exit_code}" }
|
490
|
+
else
|
491
|
+
@logger.trace { "Command #{command_str} failed with exit code #{result_output.exit_code}" }
|
492
|
+
end
|
493
|
+
result_output
|
494
|
+
rescue StandardError
|
495
|
+
# Ensure we close stdin and kill the child process
|
496
|
+
inp.close unless inp.nil? || inp.closed?
|
497
|
+
t&.terminate if t&.alive?
|
498
|
+
@logger.trace { "Command aborted" }
|
499
|
+
raise
|
500
|
+
end
|
501
|
+
|
502
|
+
def sudo_prompt
|
503
|
+
'[sudo] Bolt needs to run as another user, password: '
|
504
|
+
end
|
505
|
+
|
506
|
+
private def log_stream(to_print, stream_name)
|
507
|
+
if !to_print.chomp.empty? && @stream_logger
|
508
|
+
formatted = to_print.lines.map do |msg|
|
509
|
+
"[#{@target.safe_name}] #{stream_name}: #{msg.chomp}"
|
510
|
+
end.join("\n")
|
511
|
+
@stream_logger.warn(formatted)
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|
516
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class Shell
|
5
|
+
class Powershell < Shell
|
6
|
+
module Snippets
|
7
|
+
class << self
|
8
|
+
def execute_process(command)
|
9
|
+
<<~PS
|
10
|
+
if ([Console]::InputEncoding -eq [System.Text.Encoding]::UTF8) {
|
11
|
+
[Console]::InputEncoding = New-Object System.Text.UTF8Encoding $False
|
12
|
+
}
|
13
|
+
if ([Console]::OutputEncoding -eq [System.Text.Encoding]::UTF8) {
|
14
|
+
[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding $False
|
15
|
+
}
|
16
|
+
$OutputEncoding = [Console]::OutputEncoding
|
17
|
+
#{command}
|
18
|
+
if (-not $? -and ($LASTEXITCODE -eq $null)) { exit 1 }
|
19
|
+
exit $LASTEXITCODE
|
20
|
+
PS
|
21
|
+
end
|
22
|
+
|
23
|
+
def exit_with_code(command)
|
24
|
+
<<~PS
|
25
|
+
#{command}
|
26
|
+
if (-not $? -and ($LASTEXITCODE -eq $null)) { exit 1 }
|
27
|
+
exit $LASTEXITCODE
|
28
|
+
PS
|
29
|
+
end
|
30
|
+
|
31
|
+
def make_tmpdir(parent)
|
32
|
+
<<~PS
|
33
|
+
$parent = #{parent}
|
34
|
+
$name = [System.IO.Path]::GetRandomFileName()
|
35
|
+
$path = Join-Path $parent $name -ErrorAction Stop
|
36
|
+
New-Item -ItemType Directory -Path $path -ErrorAction Stop | Out-Null
|
37
|
+
$path
|
38
|
+
PS
|
39
|
+
end
|
40
|
+
|
41
|
+
def rmdir(dir)
|
42
|
+
<<~PS
|
43
|
+
Remove-Item -Force -Recurse -Path "#{dir}"
|
44
|
+
PS
|
45
|
+
end
|
46
|
+
|
47
|
+
def run_script(arguments, script_path)
|
48
|
+
build_arg_list = arguments.map do |a|
|
49
|
+
"$invokeArgs.ArgumentList += @'\n#{a}\n'@"
|
50
|
+
end.join("\n")
|
51
|
+
<<~PS
|
52
|
+
$invokeArgs = @{
|
53
|
+
ScriptBlock = (Get-Command "#{script_path}").ScriptBlock
|
54
|
+
ArgumentList = @()
|
55
|
+
}
|
56
|
+
#{build_arg_list}
|
57
|
+
|
58
|
+
try
|
59
|
+
{
|
60
|
+
switch -regex ( Get-ExecutionPolicy )
|
61
|
+
{
|
62
|
+
'^AllSigned'
|
63
|
+
{
|
64
|
+
if ((Get-AuthenticodeSignature -File "#{script_path}").Status -ne 'Valid') {
|
65
|
+
$Host.UI.WriteErrorLine("Error: Target host Powershell ExecutionPolicy is set to ${_} and script '#{script_path}' does not contain a valid signature.")
|
66
|
+
exit 1;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
'^Restricted'
|
70
|
+
{
|
71
|
+
$Host.UI.WriteErrorLine("Error: Target host Powershell ExecutionPolicy is set to ${_} which denies running any scripts on the target.")
|
72
|
+
exit 1;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
catch {}
|
77
|
+
|
78
|
+
if([string]::IsNullOrEmpty($invokeArgs.ScriptBlock)){
|
79
|
+
$Host.UI.WriteErrorLine("Error: Failed to obtain scriptblock from '#{script_path}'. Running scripts might be disabled on this system. For more information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170");
|
80
|
+
exit 1;
|
81
|
+
}
|
82
|
+
|
83
|
+
try
|
84
|
+
{
|
85
|
+
Invoke-Command @invokeArgs
|
86
|
+
}
|
87
|
+
catch
|
88
|
+
{
|
89
|
+
$Host.UI.WriteErrorLine("[$($_.FullyQualifiedErrorId)] Exception $($_.InvocationInfo.PositionMessage).`n$($_.Exception.Message)");
|
90
|
+
exit 1;
|
91
|
+
}
|
92
|
+
PS
|
93
|
+
end
|
94
|
+
|
95
|
+
def append_ps_module_path(directory)
|
96
|
+
<<~PS
|
97
|
+
$env:PSModulePath += ";#{directory}"
|
98
|
+
PS
|
99
|
+
end
|
100
|
+
|
101
|
+
def ps_task(path, arguments)
|
102
|
+
<<~PS
|
103
|
+
$private:tempArgs = Get-ContentAsJson (
|
104
|
+
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{Base64.encode64(JSON.dump(arguments))}'))
|
105
|
+
)
|
106
|
+
$allowedArgs = (Get-Command "#{path}").Parameters.Keys
|
107
|
+
$private:taskArgs = @{}
|
108
|
+
$private:tempArgs.Keys | ? { $allowedArgs -contains $_ } | % { $private:taskArgs[$_] = $private:tempArgs[$_] }
|
109
|
+
try {
|
110
|
+
& "#{path}" @taskArgs
|
111
|
+
} catch {
|
112
|
+
$Host.UI.WriteErrorLine("[$($_.FullyQualifiedErrorId)] Exception $($_.InvocationInfo.PositionMessage).`n$($_.Exception.Message)");
|
113
|
+
exit 1;
|
114
|
+
}
|
115
|
+
PS
|
116
|
+
end
|
117
|
+
|
118
|
+
def try_catch(command)
|
119
|
+
%(try { & "#{command}" } catch { Write-Error $_.Exception; exit 1 })
|
120
|
+
end
|
121
|
+
|
122
|
+
def shell_init
|
123
|
+
<<~PS
|
124
|
+
$installRegKey = Get-ItemProperty -Path "HKLM:\\Software\\Puppet Labs\\Puppet" -ErrorAction 0
|
125
|
+
if(![string]::IsNullOrEmpty($installRegKey.RememberedInstallDir64)){
|
126
|
+
$boltBaseDir = $installRegKey.RememberedInstallDir64
|
127
|
+
}elseif(![string]::IsNullOrEmpty($installRegKey.RememberedInstallDir)){
|
128
|
+
$boltBaseDir = $installRegKey.RememberedInstallDir
|
129
|
+
}else{
|
130
|
+
$boltBaseDir = "${ENV:ProgramFiles}\\Puppet Labs\\Puppet"
|
131
|
+
}
|
132
|
+
|
133
|
+
$ENV:PATH += ";${boltBaseDir}\\bin\\;" +
|
134
|
+
"${boltBaseDir}\\puppet\\bin;" +
|
135
|
+
"${boltBaseDir}\\sys\\ruby\\bin\\"
|
136
|
+
$ENV:RUBYLIB = "${boltBaseDir}\\puppet\\lib;" +
|
137
|
+
"${boltBaseDir}\\facter\\lib;" +
|
138
|
+
"${boltBaseDir}\\hiera\\lib;" +
|
139
|
+
$ENV:RUBYLIB
|
140
|
+
|
141
|
+
function ConvertFrom-PSCustomObject
|
142
|
+
{
|
143
|
+
PARAM([Parameter(ValueFromPipeline = $true)] $InputObject)
|
144
|
+
PROCESS {
|
145
|
+
if ($null -eq $InputObject) { return $null }
|
146
|
+
if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) {
|
147
|
+
$collection = @(
|
148
|
+
foreach ($object in $InputObject) { ConvertFrom-PSCustomObject $object }
|
149
|
+
)
|
150
|
+
|
151
|
+
$collection
|
152
|
+
} elseif ($InputObject -is [System.Management.Automation.PSCustomObject]) {
|
153
|
+
$hash = @{}
|
154
|
+
foreach ($property in $InputObject.PSObject.Properties) {
|
155
|
+
$hash[$property.Name] = ConvertFrom-PSCustomObject $property.Value
|
156
|
+
}
|
157
|
+
|
158
|
+
$hash
|
159
|
+
} else {
|
160
|
+
$InputObject
|
161
|
+
}
|
162
|
+
}
|
163
|
+
}
|
164
|
+
|
165
|
+
function Get-ContentAsJson
|
166
|
+
{
|
167
|
+
[CmdletBinding()]
|
168
|
+
PARAM(
|
169
|
+
[Parameter(Mandatory = $true)] $Text,
|
170
|
+
[Parameter(Mandatory = $false)] [Text.Encoding] $Encoding = [Text.Encoding]::UTF8
|
171
|
+
)
|
172
|
+
|
173
|
+
$Text | ConvertFrom-Json | ConvertFrom-PSCustomObject
|
174
|
+
}
|
175
|
+
PS
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|