bolt 2.17.0 → 2.22.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Puppetfile +3 -1
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +20 -9
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +123 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +6 -0
- data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +35 -0
- data/lib/bolt/applicator.rb +19 -14
- data/lib/bolt/apply_result.rb +1 -1
- data/lib/bolt/bolt_option_parser.rb +68 -13
- data/lib/bolt/catalog.rb +12 -3
- data/lib/bolt/cli.rb +232 -47
- data/lib/bolt/config.rb +34 -13
- data/lib/bolt/config/options.rb +16 -1
- data/lib/bolt/config/transport/options.rb +16 -10
- data/lib/bolt/config/transport/ssh.rb +24 -10
- data/lib/bolt/executor.rb +21 -0
- data/lib/bolt/inventory/group.rb +3 -2
- data/lib/bolt/inventory/inventory.rb +4 -3
- data/lib/bolt/logger.rb +21 -0
- data/lib/bolt/module.rb +2 -1
- data/lib/bolt/outputter/rainbow.rb +9 -2
- data/lib/bolt/pal.rb +8 -2
- data/lib/bolt/pal/yaml_plan/evaluator.rb +23 -2
- data/lib/bolt/pal/yaml_plan/step.rb +24 -2
- data/lib/bolt/pal/yaml_plan/step/download.rb +38 -0
- data/lib/bolt/pal/yaml_plan/step/message.rb +30 -0
- data/lib/bolt/pal/yaml_plan/step/upload.rb +3 -3
- data/lib/bolt/plugin/module.rb +2 -4
- data/lib/bolt/plugin/puppetdb.rb +3 -2
- data/lib/bolt/project.rb +25 -11
- data/lib/bolt/puppetdb/client.rb +2 -0
- data/lib/bolt/puppetdb/config.rb +16 -0
- data/lib/bolt/result.rb +7 -0
- data/lib/bolt/shell/bash.rb +24 -4
- data/lib/bolt/shell/powershell.rb +10 -4
- data/lib/bolt/shell/powershell/snippets.rb +15 -6
- data/lib/bolt/transport/base.rb +24 -0
- data/lib/bolt/transport/docker.rb +8 -0
- data/lib/bolt/transport/docker/connection.rb +20 -2
- data/lib/bolt/transport/local/connection.rb +14 -1
- data/lib/bolt/transport/orch.rb +12 -0
- data/lib/bolt/transport/simple.rb +6 -0
- data/lib/bolt/transport/ssh.rb +7 -1
- data/lib/bolt/transport/ssh/connection.rb +9 -1
- data/lib/bolt/transport/ssh/exec_connection.rb +23 -2
- data/lib/bolt/transport/winrm/connection.rb +118 -8
- data/lib/bolt/util.rb +26 -11
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/transport_app.rb +3 -2
- data/lib/bolt_spec/bolt_context.rb +7 -2
- data/lib/bolt_spec/plans.rb +15 -2
- data/lib/bolt_spec/plans/action_stubs.rb +2 -1
- data/lib/bolt_spec/plans/action_stubs/download_stub.rb +66 -0
- data/lib/bolt_spec/plans/mock_executor.rb +14 -1
- data/lib/bolt_spec/run.rb +22 -0
- data/libexec/bolt_catalog +3 -2
- data/modules/secure_env_vars/plans/init.pp +20 -0
- metadata +8 -2
@@ -73,7 +73,7 @@ module Bolt
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def upload_step(scope, step)
|
76
|
-
source = step['source']
|
76
|
+
source = step['upload'] || step['source']
|
77
77
|
destination = step['destination']
|
78
78
|
targets = step['targets'] || step['target']
|
79
79
|
description = step['description']
|
@@ -83,6 +83,17 @@ module Bolt
|
|
83
83
|
scope.call_function('upload_file', args)
|
84
84
|
end
|
85
85
|
|
86
|
+
def download_step(scope, step)
|
87
|
+
source = step['download']
|
88
|
+
destination = step['destination']
|
89
|
+
targets = step['targets'] || step['target']
|
90
|
+
description = step['description']
|
91
|
+
|
92
|
+
args = [source, destination, targets]
|
93
|
+
args << description if description
|
94
|
+
scope.call_function('download_file', args)
|
95
|
+
end
|
96
|
+
|
86
97
|
def eval_step(_scope, step)
|
87
98
|
step['eval']
|
88
99
|
end
|
@@ -97,6 +108,10 @@ module Bolt
|
|
97
108
|
apply_manifest(scope, targets, manifest)
|
98
109
|
end
|
99
110
|
|
111
|
+
def message_step(scope, step)
|
112
|
+
scope.call_function('out::message', step['message'])
|
113
|
+
end
|
114
|
+
|
100
115
|
def generate_manifest(resources)
|
101
116
|
# inspect returns the Ruby representation of the resource hashes,
|
102
117
|
# which happens to be the same as the Puppet representation
|
@@ -142,7 +157,13 @@ module Bolt
|
|
142
157
|
if plan.steps.any? { |step| step.body.key?('target') }
|
143
158
|
msg = "The 'target' parameter for YAML plan steps is deprecated and will be removed "\
|
144
159
|
"in a future version of Bolt. Use the 'targets' parameter instead."
|
145
|
-
|
160
|
+
Bolt::Logger.deprecation_warning("Using 'target' parameter for YAML plan steps, not 'targets'", msg)
|
161
|
+
end
|
162
|
+
|
163
|
+
if plan.steps.any? { |step| step.body.key?('source') }
|
164
|
+
msg = "The 'source' parameter for YAML plan upload steps is deprecated and will be removed "\
|
165
|
+
"in a future version of Bolt. Use the 'upload' parameter instead."
|
166
|
+
Bolt::Logger.deprecation_warning("Using 'source' parameter for YAML upload steps, not 'upload'", msg)
|
146
167
|
end
|
147
168
|
|
148
169
|
plan_result = closure_scope.with_local_scope(args_hash) do |scope|
|
@@ -12,7 +12,19 @@ module Bolt
|
|
12
12
|
Set['name', 'description', 'target', 'targets']
|
13
13
|
end
|
14
14
|
|
15
|
-
STEP_KEYS = %w[
|
15
|
+
STEP_KEYS = %w[
|
16
|
+
command
|
17
|
+
destination
|
18
|
+
download
|
19
|
+
eval
|
20
|
+
message
|
21
|
+
plan
|
22
|
+
resources
|
23
|
+
script
|
24
|
+
source
|
25
|
+
task
|
26
|
+
upload
|
27
|
+
].freeze
|
16
28
|
|
17
29
|
def self.create(step_body, step_number)
|
18
30
|
type_keys = (STEP_KEYS & step_body.keys)
|
@@ -22,8 +34,10 @@ module Bolt
|
|
22
34
|
when 1
|
23
35
|
type = type_keys.first
|
24
36
|
else
|
25
|
-
if
|
37
|
+
if [Set['source', 'destination'], Set['upload', 'destination']].include?(type_keys.to_set)
|
26
38
|
type = 'upload'
|
39
|
+
elsif type_keys.to_set == Set['download', 'destination']
|
40
|
+
type = 'download'
|
27
41
|
else
|
28
42
|
raise step_error("Multiple action keys detected: #{type_keys.inspect}", step_body['name'], step_number)
|
29
43
|
end
|
@@ -89,6 +103,12 @@ module Bolt
|
|
89
103
|
missing_keys -= ['targets']
|
90
104
|
end
|
91
105
|
|
106
|
+
# Handle cases where upload step uses deprecated 'source' key instead of 'upload'
|
107
|
+
# TODO: Remove when 'source' is removed
|
108
|
+
if body.include?('source')
|
109
|
+
missing_keys -= ['upload']
|
110
|
+
end
|
111
|
+
|
92
112
|
if missing_keys.any?
|
93
113
|
error_message = "The #{step_type.inspect} step requires: #{missing_keys.to_a.inspect} key(s)"
|
94
114
|
err = step_error(error_message, body['name'], step_number)
|
@@ -156,3 +176,5 @@ require 'bolt/pal/yaml_plan/step/resources'
|
|
156
176
|
require 'bolt/pal/yaml_plan/step/script'
|
157
177
|
require 'bolt/pal/yaml_plan/step/task'
|
158
178
|
require 'bolt/pal/yaml_plan/step/upload'
|
179
|
+
require 'bolt/pal/yaml_plan/step/download'
|
180
|
+
require 'bolt/pal/yaml_plan/step/message'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class PAL
|
5
|
+
class YamlPlan
|
6
|
+
class Step
|
7
|
+
class Download < Step
|
8
|
+
def self.allowed_keys
|
9
|
+
super + Set['download', 'destination']
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.required_keys
|
13
|
+
Set['download', 'destination', 'targets']
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(step_body)
|
17
|
+
super
|
18
|
+
@source = step_body['download']
|
19
|
+
@destination = step_body['destination']
|
20
|
+
end
|
21
|
+
|
22
|
+
def transpile
|
23
|
+
code = String.new(" ")
|
24
|
+
code << "$#{@name} = " if @name
|
25
|
+
|
26
|
+
fn = 'download_file'
|
27
|
+
args = [@source, @destination, @targets]
|
28
|
+
args << @description if @description
|
29
|
+
|
30
|
+
code << function_call(fn, args)
|
31
|
+
|
32
|
+
code << "\n"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class PAL
|
5
|
+
class YamlPlan
|
6
|
+
class Step
|
7
|
+
class Message < Step
|
8
|
+
def self.allowed_keys
|
9
|
+
super + Set['message']
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.required_keys
|
13
|
+
Set['message']
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(step_body)
|
17
|
+
super
|
18
|
+
@message = step_body['message']
|
19
|
+
end
|
20
|
+
|
21
|
+
def transpile
|
22
|
+
code = String.new(" ")
|
23
|
+
code << function_call('out::message', [@message])
|
24
|
+
code << "\n"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -6,16 +6,16 @@ module Bolt
|
|
6
6
|
class Step
|
7
7
|
class Upload < Step
|
8
8
|
def self.allowed_keys
|
9
|
-
super + Set['source', 'destination']
|
9
|
+
super + Set['source', 'destination', 'upload']
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.required_keys
|
13
|
-
Set['
|
13
|
+
Set['upload', 'destination', 'targets']
|
14
14
|
end
|
15
15
|
|
16
16
|
def initialize(step_body)
|
17
17
|
super
|
18
|
-
@source = step_body['source']
|
18
|
+
@source = step_body['upload'] || step_body['source']
|
19
19
|
@destination = step_body['destination']
|
20
20
|
end
|
21
21
|
|
data/lib/bolt/plugin/module.rb
CHANGED
@@ -184,12 +184,10 @@ module Bolt
|
|
184
184
|
# Raises a deprecation warning if the pkcs7 plugin is using deprecated keys and
|
185
185
|
# modifies the keys so they are the correct format
|
186
186
|
def handle_deprecated_pkcs7_keys(params)
|
187
|
-
if
|
188
|
-
@deprecation_warning_issued = true
|
189
|
-
|
187
|
+
if params.key?('private-key') || params.key?('public-key')
|
190
188
|
message = "pkcs7 keys 'private-key' and 'public-key' have been deprecated and will be "\
|
191
189
|
"removed in a future version of Bolt; use 'private_key' and 'public_key' instead."
|
192
|
-
|
190
|
+
Bolt::Logger.deprecation_warning('PKCS7 keys using hyphens, not underscores', message)
|
193
191
|
end
|
194
192
|
|
195
193
|
params['private_key'] = params.delete('private-key') if params.key?('private-key')
|
data/lib/bolt/plugin/puppetdb.rb
CHANGED
@@ -85,7 +85,8 @@ module Bolt
|
|
85
85
|
|
86
86
|
def resolve_facts(config, certname, target_data)
|
87
87
|
Bolt::Util.walk_vals(config) do |value|
|
88
|
-
|
88
|
+
case value
|
89
|
+
when String
|
89
90
|
if value == 'certname'
|
90
91
|
certname
|
91
92
|
else
|
@@ -94,7 +95,7 @@ module Bolt
|
|
94
95
|
# If there's no fact data this will be nil
|
95
96
|
data&.fetch('value', nil)
|
96
97
|
end
|
97
|
-
|
98
|
+
when Array, Hash
|
98
99
|
value
|
99
100
|
else
|
100
101
|
raise FactLookupError.new(value, "fact lookups must be a string")
|
data/lib/bolt/project.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'pathname'
|
4
|
-
require 'bolt/pal'
|
5
4
|
require 'bolt/config'
|
5
|
+
require 'bolt/pal'
|
6
|
+
require 'bolt/module'
|
6
7
|
|
7
8
|
module Bolt
|
8
9
|
class Project
|
@@ -16,7 +17,8 @@ module Bolt
|
|
16
17
|
}.freeze
|
17
18
|
|
18
19
|
attr_reader :path, :data, :config_file, :inventory_file, :modulepath, :hiera_config,
|
19
|
-
:puppetfile, :rerunfile, :type, :resource_types, :warnings, :project_file
|
20
|
+
:puppetfile, :rerunfile, :type, :resource_types, :warnings, :project_file,
|
21
|
+
:deprecations, :downloads, :plans_path
|
20
22
|
|
21
23
|
def self.default_project
|
22
24
|
create_project(File.expand_path(File.join('~', '.puppetlabs', 'bolt')), 'user')
|
@@ -31,6 +33,7 @@ module Bolt
|
|
31
33
|
# hierarchy, falling back to the default if we reach the root.
|
32
34
|
def self.find_boltdir(dir)
|
33
35
|
dir = Pathname.new(dir)
|
36
|
+
|
34
37
|
if (dir + BOLTDIR_NAME).directory?
|
35
38
|
create_project(dir + BOLTDIR_NAME, 'embedded')
|
36
39
|
elsif (dir + 'bolt.yaml').file? || (dir + 'bolt-project.yaml').file?
|
@@ -44,6 +47,15 @@ module Bolt
|
|
44
47
|
|
45
48
|
def self.create_project(path, type = 'option')
|
46
49
|
fullpath = Pathname.new(path).expand_path
|
50
|
+
|
51
|
+
if !Bolt::Util.windows? && type != 'environment' && fullpath.world_writable?
|
52
|
+
raise Bolt::Error.new(
|
53
|
+
"Project directory '#{fullpath}' is world-writable which poses a security risk. Set "\
|
54
|
+
"BOLT_PROJECT='#{fullpath}' to force the use of this project directory.",
|
55
|
+
"bolt/world-writable-error"
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
47
59
|
project_file = File.join(fullpath, 'bolt-project.yaml')
|
48
60
|
data = Bolt::Util.read_optional_yaml_hash(File.expand_path(project_file), 'project')
|
49
61
|
new(data, path, type)
|
@@ -51,14 +63,16 @@ module Bolt
|
|
51
63
|
|
52
64
|
def initialize(raw_data, path, type = 'option')
|
53
65
|
@path = Pathname.new(path).expand_path
|
66
|
+
|
54
67
|
@project_file = @path + 'bolt-project.yaml'
|
55
68
|
|
56
69
|
@warnings = []
|
70
|
+
@deprecations = []
|
57
71
|
if (@path + 'bolt.yaml').file? && project_file?
|
58
72
|
msg = "Project-level configuration in bolt.yaml is deprecated if using bolt-project.yaml. "\
|
59
73
|
"Transport config should be set in inventory.yaml, all other config should be set in "\
|
60
74
|
"bolt-project.yaml."
|
61
|
-
@
|
75
|
+
@deprecations << { type: 'Using bolt.yaml for project configuration', msg: msg }
|
62
76
|
end
|
63
77
|
|
64
78
|
@inventory_file = @path + 'inventory.yaml'
|
@@ -68,6 +82,8 @@ module Bolt
|
|
68
82
|
@rerunfile = @path + '.rerun.json'
|
69
83
|
@resource_types = @path + '.resource_types'
|
70
84
|
@type = type
|
85
|
+
@downloads = @path + 'downloads'
|
86
|
+
@plans_path = @path + 'plans'
|
71
87
|
|
72
88
|
tc = Bolt::Config::INVENTORY_OPTIONS.keys & raw_data.keys
|
73
89
|
if tc.any?
|
@@ -98,7 +114,7 @@ module Bolt
|
|
98
114
|
# This API is used to prepend the project as a module to Puppet's internal
|
99
115
|
# module_references list. CHANGE AT YOUR OWN RISK
|
100
116
|
def to_h
|
101
|
-
{ path: @path, name: name }
|
117
|
+
{ path: @path.to_s, name: name }
|
102
118
|
end
|
103
119
|
|
104
120
|
def eql?(other)
|
@@ -124,11 +140,9 @@ module Bolt
|
|
124
140
|
|
125
141
|
def validate
|
126
142
|
if name
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
Invalid project name '#{name}' in bolt-project.yaml; project name must match #{name_regex.inspect}
|
131
|
-
ERROR_STRING
|
143
|
+
if name !~ Bolt::Module::MODULE_NAME_REGEX
|
144
|
+
raise Bolt::ValidationError, "Invalid project name #{name.inspect.tr('"', "'")} in bolt-project.yaml; "\
|
145
|
+
"project name must match #{Bolt::Module::MODULE_NAME_REGEX.inspect}"
|
132
146
|
elsif Dir.children(Bolt::PAL::BOLTLIB_PATH).include?(name)
|
133
147
|
raise Bolt::ValidationError, "The project '#{name}' will not be loaded. The project name conflicts "\
|
134
148
|
"with a built-in Bolt module of the same name."
|
@@ -147,8 +161,8 @@ module Bolt
|
|
147
161
|
|
148
162
|
def check_deprecated_file
|
149
163
|
if (@path + 'project.yaml').file?
|
150
|
-
|
151
|
-
|
164
|
+
msg = "Project configuration file 'project.yaml' is deprecated; use 'bolt-project.yaml' instead."
|
165
|
+
Bolt::Logger.deprecation_warning('Using project.yaml instead of bolt-project.yaml', msg)
|
152
166
|
end
|
153
167
|
end
|
154
168
|
end
|
data/lib/bolt/puppetdb/client.rb
CHANGED
@@ -96,6 +96,8 @@ module Bolt
|
|
96
96
|
@http = HTTPClient.new
|
97
97
|
@http.ssl_config.set_client_cert_file(@config.cert, @config.key) if @config.cert
|
98
98
|
@http.ssl_config.add_trust_ca(@config.cacert)
|
99
|
+
@http.connect_timeout = @config.connect_timeout if @config.connect_timeout
|
100
|
+
@http.receive_timeout = @config.read_timeout if @config.read_timeout
|
99
101
|
|
100
102
|
@http
|
101
103
|
end
|
data/lib/bolt/puppetdb/config.rb
CHANGED
@@ -132,6 +132,22 @@ module Bolt
|
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|
135
|
+
def connect_timeout
|
136
|
+
validate_timeout('connect_timeout')
|
137
|
+
@settings['connect_timeout']
|
138
|
+
end
|
139
|
+
|
140
|
+
def read_timeout
|
141
|
+
validate_timeout('read_timeout')
|
142
|
+
@settings['read_timeout']
|
143
|
+
end
|
144
|
+
|
145
|
+
def validate_timeout(timeout)
|
146
|
+
unless @settings[timeout].nil? || (@settings[timeout].is_a?(Integer) && @settings[timeout] > 0)
|
147
|
+
raise Bolt::PuppetDBError, "#{timeout} must be a positive integer, received #{@settings[timeout]}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
135
151
|
def to_hash
|
136
152
|
@settings.dup
|
137
153
|
end
|
data/lib/bolt/result.rb
CHANGED
@@ -79,6 +79,13 @@ module Bolt
|
|
79
79
|
new(target, message: "Uploaded '#{source}' to '#{target.host}:#{destination}'", action: 'upload', object: source)
|
80
80
|
end
|
81
81
|
|
82
|
+
def self.for_download(target, source, destination, download)
|
83
|
+
msg = "Downloaded '#{target.host}:#{source}' to '#{destination}'"
|
84
|
+
value = { 'path' => download }
|
85
|
+
|
86
|
+
new(target, value: value, message: msg, action: 'download', object: source)
|
87
|
+
end
|
88
|
+
|
82
89
|
# Satisfies the Puppet datatypes API
|
83
90
|
def self.from_asserted_args(target, value)
|
84
91
|
new(target, value: value)
|
data/lib/bolt/shell/bash.rb
CHANGED
@@ -37,7 +37,7 @@ module Bolt
|
|
37
37
|
with_tmpdir do |dir|
|
38
38
|
basename = File.basename(source)
|
39
39
|
tmpfile = File.join(dir.to_s, basename)
|
40
|
-
conn.
|
40
|
+
conn.upload_file(source, tmpfile)
|
41
41
|
# pass over file ownership if we're using run-as to be a different user
|
42
42
|
dir.chown(run_as)
|
43
43
|
result = execute(['mv', '-f', tmpfile, destination], sudoable: true)
|
@@ -50,6 +50,27 @@ module Bolt
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
+
def download(source, destination, options = {})
|
54
|
+
running_as(options[:run_as]) do
|
55
|
+
# Target OS may be either Unix or Windows. Without knowing the target OS before-hand
|
56
|
+
# we can't assume whether the path separator is '/' or '\'. Assume we're connecting
|
57
|
+
# to a target with Unix and then check if the path exists after downloading.
|
58
|
+
download = File.join(destination, Bolt::Util.unix_basename(source))
|
59
|
+
|
60
|
+
conn.download_file(source, destination, download)
|
61
|
+
|
62
|
+
# If the download path doesn't exist, then the file was likely downloaded from Windows
|
63
|
+
# using a source path with backslashes (e.g. 'C:\Users\Administrator\foo'). The file
|
64
|
+
# should be saved to the expected location, so update the download path assuming a
|
65
|
+
# Windows basename so the result shows the correct local path.
|
66
|
+
unless File.exist?(download)
|
67
|
+
download = File.join(destination, Bolt::Util.windows_basename(source))
|
68
|
+
end
|
69
|
+
|
70
|
+
Bolt::Result.for_download(target, source, destination, download)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
53
74
|
def run_script(script, arguments, options = {})
|
54
75
|
# unpack any Sensitive data
|
55
76
|
arguments = unwrap_sensitive_args(arguments)
|
@@ -95,7 +116,7 @@ module Bolt
|
|
95
116
|
task_dir = File.join(dir.to_s, task.tasks_dir)
|
96
117
|
dir.mkdirs([task.tasks_dir] + extra_files.map { |file| File.dirname(file['name']) })
|
97
118
|
extra_files.each do |file|
|
98
|
-
conn.
|
119
|
+
conn.upload_file(file['path'], File.join(dir.to_s, file['name']))
|
99
120
|
end
|
100
121
|
end
|
101
122
|
|
@@ -257,7 +278,7 @@ module Bolt
|
|
257
278
|
def write_executable(dir, file, filename = nil)
|
258
279
|
filename ||= File.basename(file)
|
259
280
|
remote_path = File.join(dir.to_s, filename)
|
260
|
-
conn.
|
281
|
+
conn.upload_file(file, remote_path)
|
261
282
|
make_executable(remote_path)
|
262
283
|
remote_path
|
263
284
|
end
|
@@ -314,7 +335,6 @@ module Bolt
|
|
314
335
|
sudo_str = if use_sudo
|
315
336
|
sudo_exec = target.options['sudo-executable'] || "sudo"
|
316
337
|
sudo_flags = [sudo_exec, "-S", "-H", "-u", run_as, "-p", sudo_prompt]
|
317
|
-
sudo_flags += ["-E"] if options[:environment]
|
318
338
|
Shellwords.shelljoin(sudo_flags)
|
319
339
|
else
|
320
340
|
Shellwords.shelljoin(@target.options['run-as-command'] + [run_as])
|
@@ -85,7 +85,7 @@ module Bolt
|
|
85
85
|
filename ||= File.basename(file)
|
86
86
|
validate_extensions(File.extname(filename))
|
87
87
|
destination = "#{dir}\\#{filename}"
|
88
|
-
conn.
|
88
|
+
conn.upload_file(file, destination)
|
89
89
|
destination
|
90
90
|
end
|
91
91
|
|
@@ -164,10 +164,16 @@ module Bolt
|
|
164
164
|
end
|
165
165
|
|
166
166
|
def upload(source, destination, _options = {})
|
167
|
-
conn.
|
167
|
+
conn.upload_file(source, destination)
|
168
168
|
Bolt::Result.for_upload(target, source, destination)
|
169
169
|
end
|
170
170
|
|
171
|
+
def download(source, destination, _options = {})
|
172
|
+
download = File.join(destination, Bolt::Util.windows_basename(source))
|
173
|
+
conn.download_file(source, destination, download)
|
174
|
+
Bolt::Result.for_download(target, source, destination, download)
|
175
|
+
end
|
176
|
+
|
171
177
|
def run_command(command, options = {})
|
172
178
|
command = [*env_declarations(options[:env_vars]), command].join("\r\n") if options[:env_vars]
|
173
179
|
|
@@ -220,7 +226,7 @@ module Bolt
|
|
220
226
|
task_dir = File.join(dir, task.tasks_dir)
|
221
227
|
mkdirs([task_dir] + extra_files.map { |file| File.join(dir, File.dirname(file['name'])) })
|
222
228
|
extra_files.each do |file|
|
223
|
-
conn.
|
229
|
+
conn.upload_file(file['path'], File.join(dir, file['name']))
|
224
230
|
end
|
225
231
|
end
|
226
232
|
|
@@ -262,7 +268,7 @@ module Bolt
|
|
262
268
|
return with_tmpdir do |dir|
|
263
269
|
command += "\r\nif (!$?) { if($LASTEXITCODE) { exit $LASTEXITCODE } else { exit 1 } }"
|
264
270
|
script_file = File.join(dir, "#{SecureRandom.uuid}_wrapper.ps1")
|
265
|
-
conn.
|
271
|
+
conn.upload_file(StringIO.new(command), script_file)
|
266
272
|
args = escape_arguments([script_file])
|
267
273
|
script_invocation = ['powershell.exe', *PS_ARGS, '-File', *args].join(' ')
|
268
274
|
execute(script_invocation)
|