bolt 1.12.0 → 1.13.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/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +4 -3
- data/bolt-modules/boltlib/lib/puppet/functions/add_to_group.rb +7 -0
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +8 -0
- data/bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb +7 -0
- data/bolt-modules/boltlib/lib/puppet/functions/get_resources.rb +7 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +6 -6
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +4 -3
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +6 -6
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +5 -4
- data/bolt-modules/boltlib/lib/puppet/functions/set_feature.rb +5 -4
- data/bolt-modules/boltlib/lib/puppet/functions/set_var.rb +4 -3
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +6 -6
- data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +6 -5
- data/bolt-modules/boltlib/lib/puppet/functions/without_default_logging.rb +8 -0
- data/lib/bolt/config.rb +14 -26
- data/lib/bolt/pal.rb +1 -0
- data/lib/bolt/pal/issues.rb +13 -0
- data/lib/bolt/transport/base.rb +8 -0
- data/lib/bolt/transport/docker.rb +6 -6
- data/lib/bolt/transport/docker/connection.rb +7 -4
- data/lib/bolt/transport/local.rb +25 -10
- data/lib/bolt/transport/local/shell.rb +1 -0
- data/lib/bolt/transport/orch.rb +4 -0
- data/lib/bolt/transport/remote.rb +4 -0
- data/lib/bolt/transport/ssh.rb +10 -1
- data/lib/bolt/transport/ssh/connection.rb +4 -0
- data/lib/bolt/transport/winrm.rb +24 -2
- data/lib/bolt/transport/winrm/connection.rb +112 -2
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/schemas/ssh-run_task.json +4 -0
- data/lib/bolt_server/schemas/winrm-run_task.json +14 -0
- data/lib/bolt_spec/plans.rb +5 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 66234162abaa83dd3dd590b21dd87a54d10c3da44f0d50ccd8e28d82ddf76178
|
4
|
+
data.tar.gz: b056cb53e8fda46db48b7a7a1b63f8441f80342e11e5c0a7c50d1813cf852bbc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '079515ce4801e6913e2b75d276289985cf9eda0d9b60c10021a5b435c77ce69d0cc07d5a1708a4f7c43db4947fef918f5d14b8ccac8fdf6a55b5ccf5fce6cf62'
|
7
|
+
data.tar.gz: 94eba8ff4a83d463f4b5516eb69cd83d31b1fdc6c3673a0b0beda9ac5dc08becd9eb2d75953932c57345ab8099900884174df329d04f43637802df73a538a365
|
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'bolt/error'
|
4
4
|
|
5
5
|
# Deep merges a hash of facts with the existing facts on a target.
|
6
|
+
#
|
7
|
+
# **NOTE:** Not available in apply block
|
6
8
|
Puppet::Functions.create_function(:add_facts) do
|
7
9
|
# @param target A target.
|
8
10
|
# @param facts A hash of fact names to values that may include structured facts.
|
@@ -17,9 +19,8 @@ Puppet::Functions.create_function(:add_facts) do
|
|
17
19
|
|
18
20
|
def add_facts(target, facts)
|
19
21
|
unless Puppet[:tasks]
|
20
|
-
raise Puppet::ParseErrorWithIssue
|
21
|
-
|
22
|
-
)
|
22
|
+
raise Puppet::ParseErrorWithIssue
|
23
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'add_facts')
|
23
24
|
end
|
24
25
|
|
25
26
|
inventory = Puppet.lookup(:bolt_inventory) { nil }
|
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'bolt/error'
|
4
4
|
|
5
5
|
# Adds a target to specified inventory group.
|
6
|
+
#
|
7
|
+
# **NOTE:** Not available in apply block
|
6
8
|
Puppet::Functions.create_function(:add_to_group) do
|
7
9
|
# @param targets A pattern or array of patterns identifying a set of targets.
|
8
10
|
# @param group The name of the group to add targets to.
|
@@ -20,6 +22,11 @@ Puppet::Functions.create_function(:add_to_group) do
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def add_to_group(targets, group)
|
25
|
+
unless Puppet[:tasks]
|
26
|
+
raise Puppet::ParseErrorWithIssue
|
27
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'add_to_group')
|
28
|
+
end
|
29
|
+
|
23
30
|
inventory = Puppet.lookup(:bolt_inventory) { nil }
|
24
31
|
|
25
32
|
unless inventory && Puppet.features.bolt?
|
@@ -10,6 +10,8 @@ require 'bolt/task'
|
|
10
10
|
#
|
11
11
|
# If no agent is detected on the target using the 'puppet_agent::version' task, it's installed
|
12
12
|
# using 'puppet_agent::install' and the puppet service is stopped/disabled using the 'service' task.
|
13
|
+
#
|
14
|
+
# **NOTE:** Not available in apply block
|
13
15
|
Puppet::Functions.create_function(:apply_prep) do
|
14
16
|
# @param targets A pattern or array of patterns identifying a set of targets.
|
15
17
|
# @example Prepare targets by name.
|
@@ -39,9 +41,15 @@ Puppet::Functions.create_function(:apply_prep) do
|
|
39
41
|
end
|
40
42
|
|
41
43
|
def apply_prep(target_spec)
|
44
|
+
unless Puppet[:tasks]
|
45
|
+
raise Puppet::ParseErrorWithIssue
|
46
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'apply_prep')
|
47
|
+
end
|
48
|
+
|
42
49
|
applicator = Puppet.lookup(:apply_executor) { nil }
|
43
50
|
executor = Puppet.lookup(:bolt_executor) { nil }
|
44
51
|
inventory = Puppet.lookup(:bolt_inventory) { nil }
|
52
|
+
|
45
53
|
unless applicator && executor && inventory && Puppet.features.bolt?
|
46
54
|
raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
|
47
55
|
Puppet::Pops::Issues::TASK_MISSING_BOLT, action: _('apply_prep')
|
@@ -6,6 +6,8 @@ require 'bolt/error'
|
|
6
6
|
#
|
7
7
|
# Plan authors should call this function when their plan is not successful. The
|
8
8
|
# error may then be caught by another plans run_plan function or in bolt itself
|
9
|
+
#
|
10
|
+
# **NOTE:** Not available in apply block
|
9
11
|
Puppet::Functions.create_function(:fail_plan) do
|
10
12
|
# Fail a plan, generating an exception from the parameters.
|
11
13
|
# @param msg An error message.
|
@@ -32,6 +34,11 @@ Puppet::Functions.create_function(:fail_plan) do
|
|
32
34
|
end
|
33
35
|
|
34
36
|
def from_args(msg, kind = nil, details = nil, issue_code = nil)
|
37
|
+
unless Puppet[:tasks]
|
38
|
+
raise Puppet::ParseErrorWithIssue
|
39
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'fail_plan')
|
40
|
+
end
|
41
|
+
|
35
42
|
executor = Puppet.lookup(:bolt_executor) { nil }
|
36
43
|
executor&.report_function_call('fail_plan')
|
37
44
|
|
@@ -7,6 +7,8 @@ require 'bolt/task'
|
|
7
7
|
#
|
8
8
|
# Requires the Puppet Agent be installed on the target, which can be accomplished with apply_prep
|
9
9
|
# or by directly running the puppet_agent::install task.
|
10
|
+
#
|
11
|
+
# **NOTE:** Not available in apply block
|
10
12
|
Puppet::Functions.create_function(:get_resources) do
|
11
13
|
# @param targets A pattern or array of patterns identifying a set of targets.
|
12
14
|
# @param resources A resource type or instance, or an array of such.
|
@@ -32,6 +34,11 @@ Puppet::Functions.create_function(:get_resources) do
|
|
32
34
|
end
|
33
35
|
|
34
36
|
def get_resources(target_spec, resources)
|
37
|
+
unless Puppet[:tasks]
|
38
|
+
raise Puppet::ParseErrorWithIssue
|
39
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'get_resources')
|
40
|
+
end
|
41
|
+
|
35
42
|
applicator = Puppet.lookup(:apply_executor) { nil }
|
36
43
|
executor = Puppet.lookup(:bolt_executor) { nil }
|
37
44
|
inventory = Puppet.lookup(:bolt_inventory) { nil }
|
@@ -4,6 +4,8 @@ require 'bolt/error'
|
|
4
4
|
|
5
5
|
# Runs a command on the given set of targets and returns the result from each command execution.
|
6
6
|
# This function does nothing if the list of targets is empty.
|
7
|
+
#
|
8
|
+
# **NOTE:** Not available in apply block
|
7
9
|
Puppet::Functions.create_function(:run_command) do
|
8
10
|
# Run a command.
|
9
11
|
# @param command A command to run on target.
|
@@ -40,15 +42,13 @@ Puppet::Functions.create_function(:run_command) do
|
|
40
42
|
end
|
41
43
|
|
42
44
|
def run_command_with_description(command, targets, description = nil, options = nil)
|
43
|
-
options ||= {}
|
44
|
-
options = options.merge('_description' => description) if description
|
45
|
-
|
46
45
|
unless Puppet[:tasks]
|
47
|
-
raise Puppet::ParseErrorWithIssue
|
48
|
-
|
49
|
-
)
|
46
|
+
raise Puppet::ParseErrorWithIssue
|
47
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'run_command')
|
50
48
|
end
|
51
49
|
|
50
|
+
options ||= {}
|
51
|
+
options = options.merge('_description' => description) if description
|
52
52
|
executor = Puppet.lookup(:bolt_executor) { nil }
|
53
53
|
inventory = Puppet.lookup(:bolt_inventory) { nil }
|
54
54
|
unless executor && inventory && Puppet.features.bolt?
|
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'bolt/error'
|
4
4
|
|
5
5
|
# Runs the `plan` referenced by its name. A plan is autoloaded from `<moduleroot>/plans`.
|
6
|
+
#
|
7
|
+
# **NOTE:** Not available in apply block
|
6
8
|
Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction) do
|
7
9
|
# @param plan_name The plan to run.
|
8
10
|
# @param named_args Arguments to the plan. Can also include additional options: '_catch_errors', '_run_as'.
|
@@ -18,9 +20,8 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
|
|
18
20
|
|
19
21
|
def run_plan(scope, plan_name, named_args = {})
|
20
22
|
unless Puppet[:tasks]
|
21
|
-
raise Puppet::ParseErrorWithIssue
|
22
|
-
|
23
|
-
)
|
23
|
+
raise Puppet::ParseErrorWithIssue
|
24
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'run_plan')
|
24
25
|
end
|
25
26
|
|
26
27
|
executor = Puppet.lookup(:bolt_executor) { nil }
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
# Uploads the given script to the given set of targets and returns the result of having each target execute the script.
|
4
4
|
# This function does nothing if the list of targets is empty.
|
5
|
+
#
|
6
|
+
# **NOTE:** Not available in apply block
|
5
7
|
Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFunction) do
|
6
8
|
# Run a script.
|
7
9
|
# @param script Path to a script to run on target. May be an absolute path or a modulename/filename selector for a
|
@@ -46,15 +48,13 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti
|
|
46
48
|
end
|
47
49
|
|
48
50
|
def run_script_with_description(scope, script, targets, description = nil, options = nil)
|
49
|
-
options ||= {}
|
50
|
-
options = options.merge('_description' => description) if description
|
51
|
-
|
52
51
|
unless Puppet[:tasks]
|
53
|
-
raise Puppet::ParseErrorWithIssue
|
54
|
-
|
55
|
-
)
|
52
|
+
raise Puppet::ParseErrorWithIssue
|
53
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'run_script')
|
56
54
|
end
|
57
55
|
|
56
|
+
options ||= {}
|
57
|
+
options = options.merge('_description' => description) if description
|
58
58
|
executor = Puppet.lookup(:bolt_executor) { nil }
|
59
59
|
inventory = Puppet.lookup(:bolt_inventory) { nil }
|
60
60
|
unless executor && inventory && Puppet.features.bolt?
|
@@ -6,6 +6,8 @@ require 'bolt/task'
|
|
6
6
|
|
7
7
|
# Runs a given instance of a `Task` on the given set of targets and returns the result from each.
|
8
8
|
# This function does nothing if the list of targets is empty.
|
9
|
+
#
|
10
|
+
# **NOTE:** Not available in apply block
|
9
11
|
Puppet::Functions.create_function(:run_task) do
|
10
12
|
# Run a task.
|
11
13
|
# @param task_name The task to run.
|
@@ -67,13 +69,12 @@ Puppet::Functions.create_function(:run_task) do
|
|
67
69
|
end
|
68
70
|
|
69
71
|
def run_task_raw(task_name, targets, description = nil, task_args = nil, &block)
|
70
|
-
task_args ||= {}
|
71
72
|
unless Puppet[:tasks]
|
72
|
-
raise Puppet::ParseErrorWithIssue
|
73
|
-
|
74
|
-
)
|
73
|
+
raise Puppet::ParseErrorWithIssue
|
74
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'run_task')
|
75
75
|
end
|
76
76
|
|
77
|
+
task_args ||= {}
|
77
78
|
executor = Puppet.lookup(:bolt_executor) { nil }
|
78
79
|
inventory = Puppet.lookup(:bolt_inventory) { nil }
|
79
80
|
unless executor && inventory && Puppet.features.bolt?
|
@@ -9,11 +9,13 @@ require 'bolt/error'
|
|
9
9
|
# - powershell
|
10
10
|
# - shell
|
11
11
|
# - puppet-agent
|
12
|
+
#
|
13
|
+
# **NOTE:** Not available in apply block
|
12
14
|
Puppet::Functions.create_function(:set_feature) do
|
13
15
|
# @param target The Target object to add features to. See {get_targets}.
|
14
16
|
# @param feature The string identifying the feature.
|
15
17
|
# @param value Whether the feature is supported.
|
16
|
-
# @return
|
18
|
+
# @return The target with the updated feature
|
17
19
|
# @example Add the puppet-agent feature to a target
|
18
20
|
# set_feature($target, 'puppet-agent', true)
|
19
21
|
dispatch :set_feature do
|
@@ -24,9 +26,8 @@ Puppet::Functions.create_function(:set_feature) do
|
|
24
26
|
|
25
27
|
def set_feature(target, feature, value = true)
|
26
28
|
unless Puppet[:tasks]
|
27
|
-
raise Puppet::ParseErrorWithIssue
|
28
|
-
|
29
|
-
)
|
29
|
+
raise Puppet::ParseErrorWithIssue
|
30
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'set_feature')
|
30
31
|
end
|
31
32
|
|
32
33
|
inventory = Puppet.lookup(:bolt_inventory) { nil }
|
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'bolt/error'
|
4
4
|
|
5
5
|
# Sets a variable { key => value } for a target.
|
6
|
+
#
|
7
|
+
# **NOTE:** Not available in apply block
|
6
8
|
Puppet::Functions.create_function(:set_var) do
|
7
9
|
# @param target The Target object to set the variable for. See {get_targets}.
|
8
10
|
# @param key The key for the variable.
|
@@ -18,9 +20,8 @@ Puppet::Functions.create_function(:set_var) do
|
|
18
20
|
|
19
21
|
def set_var(target, key, value)
|
20
22
|
unless Puppet[:tasks]
|
21
|
-
raise Puppet::ParseErrorWithIssue
|
22
|
-
|
23
|
-
)
|
23
|
+
raise Puppet::ParseErrorWithIssue
|
24
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'set_var')
|
24
25
|
end
|
25
26
|
|
26
27
|
inventory = Puppet.lookup(:bolt_inventory) { nil }
|
@@ -4,6 +4,8 @@ require 'bolt/error'
|
|
4
4
|
|
5
5
|
# Uploads the given file or directory to the given set of targets and returns the result from each upload.
|
6
6
|
# This function does nothing if the list of targets is empty.
|
7
|
+
#
|
8
|
+
# **NOTE:** Not available in apply block
|
7
9
|
Puppet::Functions.create_function(:upload_file, Puppet::Functions::InternalFunction) do
|
8
10
|
# Upload a file.
|
9
11
|
# @param source A source path, either an absolute path or a modulename/filename selector for a file in
|
@@ -50,15 +52,13 @@ Puppet::Functions.create_function(:upload_file, Puppet::Functions::InternalFunct
|
|
50
52
|
end
|
51
53
|
|
52
54
|
def upload_file_with_description(scope, source, destination, targets, description = nil, options = nil)
|
53
|
-
options ||= {}
|
54
|
-
options = options.merge('_description' => description) if description
|
55
|
-
|
56
55
|
unless Puppet[:tasks]
|
57
|
-
raise Puppet::ParseErrorWithIssue
|
58
|
-
|
59
|
-
)
|
56
|
+
raise Puppet::ParseErrorWithIssue
|
57
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'upload_file')
|
60
58
|
end
|
61
59
|
|
60
|
+
options ||= {}
|
61
|
+
options = options.merge('_description' => description) if description
|
62
62
|
executor = Puppet.lookup(:bolt_executor) { nil }
|
63
63
|
inventory = Puppet.lookup(:bolt_inventory) { nil }
|
64
64
|
unless executor && inventory && Puppet.features.bolt?
|
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'bolt/util'
|
4
4
|
|
5
5
|
# Wait until all targets accept connections.
|
6
|
+
#
|
7
|
+
# **NOTE:** Not available in apply block
|
6
8
|
Puppet::Functions.create_function(:wait_until_available) do
|
7
9
|
# Wait until targets are available.
|
8
10
|
# @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
|
@@ -17,14 +19,13 @@ Puppet::Functions.create_function(:wait_until_available) do
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def wait_until_available(targets, options = nil)
|
20
|
-
options ||= {}
|
21
|
-
|
22
22
|
unless Puppet[:tasks]
|
23
|
-
raise Puppet::ParseErrorWithIssue
|
24
|
-
|
25
|
-
|
23
|
+
raise Puppet::ParseErrorWithIssue
|
24
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING,
|
25
|
+
action: 'wait_until_available')
|
26
26
|
end
|
27
27
|
|
28
|
+
options ||= {}
|
28
29
|
executor = Puppet.lookup(:bolt_executor) { nil }
|
29
30
|
inventory = Puppet.lookup(:bolt_inventory) { nil }
|
30
31
|
unless executor && inventory && Puppet.features.bolt?
|
@@ -5,6 +5,8 @@
|
|
5
5
|
# Messages for actions within this block will be logged at `info` level instead
|
6
6
|
# of `notice`, so they will not be seen normally but # will still be present
|
7
7
|
# when `verbose` logging is requested.
|
8
|
+
#
|
9
|
+
# **NOTE:** Not available in apply block
|
8
10
|
Puppet::Functions.create_function(:without_default_logging) do
|
9
11
|
# @param block The block where action logging is suppressed.
|
10
12
|
# @return [Undef]
|
@@ -20,6 +22,12 @@ Puppet::Functions.create_function(:without_default_logging) do
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def without_default_logging
|
25
|
+
unless Puppet[:tasks]
|
26
|
+
raise Puppet::ParseErrorWithIssue
|
27
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING,
|
28
|
+
action: 'without_default_logging')
|
29
|
+
end
|
30
|
+
|
23
31
|
executor = Puppet.lookup(:bolt_executor) { nil }
|
24
32
|
executor.report_function_call('without_default_logging')
|
25
33
|
|
data/lib/bolt/config.rb
CHANGED
@@ -36,29 +36,7 @@ module Bolt
|
|
36
36
|
|
37
37
|
TRANSPORT_OPTIONS = %i[password run-as sudo-password extensions
|
38
38
|
private-key tty tmpdir user connect-timeout
|
39
|
-
cacert token-file service-url].freeze
|
40
|
-
|
41
|
-
# TODO: move these to the transport themselves
|
42
|
-
TRANSPORT_SPECIFIC_DEFAULTS = {
|
43
|
-
ssh: {
|
44
|
-
'connect-timeout' => 10,
|
45
|
-
'host-key-check' => true,
|
46
|
-
'tty' => false
|
47
|
-
},
|
48
|
-
winrm: {
|
49
|
-
'connect-timeout' => 10,
|
50
|
-
'ssl' => true,
|
51
|
-
'ssl-verify' => true
|
52
|
-
},
|
53
|
-
pcp: {
|
54
|
-
'task-environment' => 'production'
|
55
|
-
},
|
56
|
-
local: {},
|
57
|
-
docker: {},
|
58
|
-
remote: {
|
59
|
-
'run-on' => 'localhost'
|
60
|
-
}
|
61
|
-
}.freeze
|
39
|
+
cacert token-file service-url interpreters file-protocol smb-port].freeze
|
62
40
|
|
63
41
|
def self.default
|
64
42
|
new(Bolt::Boltdir.new('.'), {})
|
@@ -91,8 +69,9 @@ module Bolt
|
|
91
69
|
@log = { 'console' => {} }
|
92
70
|
|
93
71
|
@transports = {}
|
94
|
-
|
95
|
-
|
72
|
+
|
73
|
+
TRANSPORTS.each do |key, transport|
|
74
|
+
@transports[key] = transport.default_options
|
96
75
|
end
|
97
76
|
|
98
77
|
update_from_file(config_data)
|
@@ -114,6 +93,12 @@ module Bolt
|
|
114
93
|
Bolt::Util.deep_clone(self)
|
115
94
|
end
|
116
95
|
|
96
|
+
def normalize_interpreters(interpreters)
|
97
|
+
Bolt::Util.walk_keys(interpreters) do |key|
|
98
|
+
key.chars[0] == '.' ? key : '.' + key
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
117
102
|
def normalize_log(target)
|
118
103
|
return target if target == 'console'
|
119
104
|
target = target[5..-1] if target.start_with?('file:')
|
@@ -168,7 +153,10 @@ module Bolt
|
|
168
153
|
TRANSPORTS.each do |key, impl|
|
169
154
|
if data[key.to_s]
|
170
155
|
selected = impl.filter_options(data[key.to_s])
|
171
|
-
@transports[key].
|
156
|
+
@transports[key] = Bolt::Util.deep_merge(@transports[key], selected)
|
157
|
+
end
|
158
|
+
if @transports[key]['interpreters']
|
159
|
+
@transports[key]['interpreters'] = normalize_interpreters(@transports[key]['interpreters'])
|
172
160
|
end
|
173
161
|
end
|
174
162
|
end
|
data/lib/bolt/pal.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class PAL
|
5
|
+
module Issues
|
6
|
+
# Create issue using Issues api
|
7
|
+
PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING =
|
8
|
+
Puppet::Pops::Issues.issue :PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, :action do
|
9
|
+
"Plan language function '#{action}' cannot be used from declarative manifest code or apply blocks"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/bolt/transport/base.rb
CHANGED
@@ -48,6 +48,10 @@ module Bolt
|
|
48
48
|
"self.options() or self.filter_options(unfiltered) must be implemented by the transport class"
|
49
49
|
end
|
50
50
|
|
51
|
+
def self.default_options
|
52
|
+
{}
|
53
|
+
end
|
54
|
+
|
51
55
|
def self.filter_options(unfiltered)
|
52
56
|
unfiltered.select { |k| options.include?(k) }
|
53
57
|
end
|
@@ -87,6 +91,10 @@ module Bolt
|
|
87
91
|
impl
|
88
92
|
end
|
89
93
|
|
94
|
+
def select_interpreter(executable, interpreters)
|
95
|
+
interpreters[Pathname(executable).extname] if interpreters
|
96
|
+
end
|
97
|
+
|
90
98
|
def reject_transport_options(target, options)
|
91
99
|
if target.options['run-as']
|
92
100
|
options.reject { |k, _v| k == '_run_as' }
|
@@ -8,7 +8,7 @@ module Bolt
|
|
8
8
|
module Transport
|
9
9
|
class Docker < Base
|
10
10
|
def self.options
|
11
|
-
%w[service-url service-options tmpdir]
|
11
|
+
%w[service-url service-options tmpdir interpreters]
|
12
12
|
end
|
13
13
|
|
14
14
|
def provided_features
|
@@ -48,7 +48,7 @@ module Bolt
|
|
48
48
|
|
49
49
|
_, stderr, exitcode = conn.execute('mv', tmpfile, destination, {})
|
50
50
|
if exitcode != 0
|
51
|
-
message = "Could not move temporary file '#{tmpfile}' to #{destination}: #{stderr
|
51
|
+
message = "Could not move temporary file '#{tmpfile}' to #{destination}: #{stderr}"
|
52
52
|
raise Bolt::Node::FileError.new(message, 'MV_ERROR')
|
53
53
|
end
|
54
54
|
end
|
@@ -59,7 +59,7 @@ module Bolt
|
|
59
59
|
def run_command(target, command, _options = {})
|
60
60
|
with_connection(target) do |conn|
|
61
61
|
stdout, stderr, exitcode = conn.execute(*Shellwords.split(command), {})
|
62
|
-
Bolt::Result.for_command(target, stdout
|
62
|
+
Bolt::Result.for_command(target, stdout, stderr, exitcode)
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -71,7 +71,7 @@ module Bolt
|
|
71
71
|
conn.with_remote_tempdir do |dir|
|
72
72
|
remote_path = conn.write_remote_executable(dir, script)
|
73
73
|
stdout, stderr, exitcode = conn.execute(remote_path, *arguments, {})
|
74
|
-
Bolt::Result.for_command(target, stdout
|
74
|
+
Bolt::Result.for_command(target, stdout, stderr, exitcode)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
@@ -87,7 +87,7 @@ module Bolt
|
|
87
87
|
arguments = unwrap_sensitive_args(arguments)
|
88
88
|
with_connection(target) do |conn|
|
89
89
|
execute_options = {}
|
90
|
-
|
90
|
+
execute_options[:interpreter] = select_interpreter(executable, target.options['interpreters'])
|
91
91
|
conn.with_remote_tempdir do |dir|
|
92
92
|
if extra_files.empty?
|
93
93
|
task_dir = dir
|
@@ -112,7 +112,7 @@ module Bolt
|
|
112
112
|
end
|
113
113
|
|
114
114
|
stdout, stderr, exitcode = conn.execute(remote_task_path, execute_options)
|
115
|
-
Bolt::Result.for_task(target, stdout
|
115
|
+
Bolt::Result.for_task(target, stdout, stderr, exitcode)
|
116
116
|
end
|
117
117
|
end
|
118
118
|
end
|
@@ -27,6 +27,7 @@ module Bolt
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def execute(*command, options)
|
30
|
+
command.unshift(options[:interpreter]) if options[:interpreter]
|
30
31
|
if options[:environment]
|
31
32
|
envs = options[:environment].map { |env, val| "#{env}=#{val}" }
|
32
33
|
command = ['env'] + envs + command
|
@@ -39,6 +40,8 @@ module Bolt
|
|
39
40
|
else
|
40
41
|
@logger.info { "Command failed with exit code #{result[2]}" }
|
41
42
|
end
|
43
|
+
result[0] = result[0].join.force_encoding('UTF-8')
|
44
|
+
result[1] = result[1].join.force_encoding('UTF-8')
|
42
45
|
result
|
43
46
|
rescue StandardError
|
44
47
|
@logger.debug { "Command aborted" }
|
@@ -62,7 +65,7 @@ module Bolt
|
|
62
65
|
def mkdirs(dirs)
|
63
66
|
_, stderr, exitcode = execute('mkdir', '-p', *dirs, {})
|
64
67
|
if exitcode != 0
|
65
|
-
message = "Could not create directories: #{stderr
|
68
|
+
message = "Could not create directories: #{stderr}"
|
66
69
|
raise Bolt::Node::FileError.new(message, 'MKDIR_ERROR')
|
67
70
|
end
|
68
71
|
end
|
@@ -73,7 +76,7 @@ module Bolt
|
|
73
76
|
|
74
77
|
stdout, stderr, exitcode = execute('mkdir', '-m', '700', tmppath, {})
|
75
78
|
if exitcode != 0
|
76
|
-
raise Bolt::Node::FileError.new("Could not make tempdir: #{stderr
|
79
|
+
raise Bolt::Node::FileError.new("Could not make tempdir: #{stderr}", 'TEMPDIR_ERROR')
|
77
80
|
end
|
78
81
|
tmppath || stdout.first
|
79
82
|
end
|
@@ -85,7 +88,7 @@ module Bolt
|
|
85
88
|
if dir
|
86
89
|
_, stderr, exitcode = execute('rm', '-rf', dir, {})
|
87
90
|
if exitcode != 0
|
88
|
-
@logger.warn("Failed to clean up tempdir '#{dir}': #{stderr
|
91
|
+
@logger.warn("Failed to clean up tempdir '#{dir}': #{stderr}")
|
89
92
|
end
|
90
93
|
end
|
91
94
|
end
|
@@ -101,7 +104,7 @@ module Bolt
|
|
101
104
|
def make_executable(path)
|
102
105
|
_, stderr, exitcode = execute('chmod', 'u+x', path, {})
|
103
106
|
if exitcode != 0
|
104
|
-
message = "Could not make file '#{path}' executable: #{stderr
|
107
|
+
message = "Could not make file '#{path}' executable: #{stderr}"
|
105
108
|
raise Bolt::Node::FileError.new(message, 'CHMOD_ERROR')
|
106
109
|
end
|
107
110
|
end
|
data/lib/bolt/transport/local.rb
CHANGED
@@ -11,7 +11,13 @@ module Bolt
|
|
11
11
|
module Transport
|
12
12
|
class Local < Base
|
13
13
|
def self.options
|
14
|
-
%w[tmpdir]
|
14
|
+
%w[tmpdir interpreters]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.default_options
|
18
|
+
{
|
19
|
+
'interpreters' => { '.rb' => RbConfig.ruby }
|
20
|
+
}
|
15
21
|
end
|
16
22
|
|
17
23
|
def provided_features
|
@@ -129,8 +135,10 @@ module Bolt
|
|
129
135
|
copy_file(executable, script)
|
130
136
|
File.chmod(0o750, script)
|
131
137
|
|
138
|
+
interpreter = select_interpreter(script, target.options['interpreters'])
|
139
|
+
interpreter_debug = interpreter ? " using '#{interpreter}' interpreter" : nil
|
132
140
|
# log the arguments with sensitive data redacted, do NOT log unwrapped_arguments
|
133
|
-
logger.debug("Running '#{script}' with #{arguments}")
|
141
|
+
logger.debug("Running '#{script}' with #{arguments}#{interpreter_debug}")
|
134
142
|
unwrapped_arguments = unwrap_sensitive_args(arguments)
|
135
143
|
|
136
144
|
stdin = STDIN_METHODS.include?(input_method) ? JSON.dump(unwrapped_arguments) : nil
|
@@ -146,25 +154,32 @@ module Bolt
|
|
146
154
|
environment_params = ""
|
147
155
|
end
|
148
156
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
157
|
+
if Powershell.powershell_file?(script) && stdin.nil?
|
158
|
+
command = Powershell.run_ps_task(arguments, script, input_method)
|
159
|
+
command = environment_params + Powershell.shell_init + command
|
160
|
+
interpreter ||= 'powershell.exe'
|
161
|
+
output =
|
153
162
|
if input_method == 'powershell'
|
154
|
-
@conn.execute(command, dir: dir,
|
163
|
+
@conn.execute(command, dir: dir, interpreter: interpreter)
|
155
164
|
else
|
156
|
-
@conn.execute(command, dir: dir, stdin: stdin,
|
165
|
+
@conn.execute(command, dir: dir, stdin: stdin, interpreter: interpreter)
|
157
166
|
end
|
167
|
+
end
|
168
|
+
unless output
|
169
|
+
if interpreter
|
170
|
+
env = ENVIRONMENT_METHODS.include?(input_method) ? envify_params(unwrapped_arguments) : nil
|
171
|
+
output = @conn.execute(script, stdin: stdin, env: env, dir: dir, interpreter: interpreter)
|
158
172
|
else
|
159
173
|
path, args = *Powershell.process_from_extension(script)
|
160
174
|
command = args.unshift(path).join(' ')
|
161
175
|
command = environment_params + Powershell.shell_init + command
|
162
|
-
@conn.execute(command, dir: dir, stdin: stdin,
|
176
|
+
output = @conn.execute(command, dir: dir, stdin: stdin, interpreter: 'powershell.exe')
|
163
177
|
end
|
178
|
+
end
|
164
179
|
else
|
165
180
|
# POSIX
|
166
181
|
env = ENVIRONMENT_METHODS.include?(input_method) ? envify_params(unwrapped_arguments) : nil
|
167
|
-
output = @conn.execute(script, stdin: stdin, env: env, dir: dir)
|
182
|
+
output = @conn.execute(script, stdin: stdin, env: env, dir: dir, interpreter: interpreter)
|
168
183
|
end
|
169
184
|
Bolt::Result.for_task(target, output.stdout.string, output.stderr.string, output.exit_code)
|
170
185
|
end
|
data/lib/bolt/transport/orch.rb
CHANGED
data/lib/bolt/transport/ssh.rb
CHANGED
@@ -10,7 +10,15 @@ module Bolt
|
|
10
10
|
class SSH < Base
|
11
11
|
def self.options
|
12
12
|
%w[port user password sudo-password private-key host-key-check
|
13
|
-
connect-timeout tmpdir run-as tty run-as-command proxyjump]
|
13
|
+
connect-timeout tmpdir run-as tty run-as-command proxyjump interpreters]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.default_options
|
17
|
+
{
|
18
|
+
'connect-timeout' => 10,
|
19
|
+
'host-key-check' => true,
|
20
|
+
'tty' => false
|
21
|
+
}
|
14
22
|
end
|
15
23
|
|
16
24
|
def provided_features
|
@@ -169,6 +177,7 @@ module Bolt
|
|
169
177
|
dir.chown(conn.run_as)
|
170
178
|
|
171
179
|
execute_options[:sudoable] = true if conn.run_as
|
180
|
+
execute_options[:interpreter] = select_interpreter(executable, target.options['interpreters'])
|
172
181
|
output = conn.execute(command, execute_options)
|
173
182
|
end
|
174
183
|
Bolt::Result.for_task(target, output.stdout.string,
|
@@ -227,6 +227,10 @@ module Bolt
|
|
227
227
|
escalate = sudoable && run_as && @user != run_as
|
228
228
|
use_sudo = escalate && @target.options['run-as-command'].nil?
|
229
229
|
|
230
|
+
if options[:interpreter]
|
231
|
+
command.is_a?(Array) ? command.unshift(options[:interpreter]) : [options[:interpreter], command]
|
232
|
+
end
|
233
|
+
|
230
234
|
command_str = command.is_a?(String) ? command : Shellwords.shelljoin(command)
|
231
235
|
if escalate
|
232
236
|
if use_sudo
|
data/lib/bolt/transport/winrm.rb
CHANGED
@@ -8,7 +8,19 @@ module Bolt
|
|
8
8
|
module Transport
|
9
9
|
class WinRM < Base
|
10
10
|
def self.options
|
11
|
-
%w[
|
11
|
+
%w[
|
12
|
+
port user password connect-timeout ssl ssl-verify tmpdir cacert
|
13
|
+
extensions interpreters file-protocol smb-port
|
14
|
+
]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.default_options
|
18
|
+
{
|
19
|
+
'connect-timeout' => 10,
|
20
|
+
'ssl' => true,
|
21
|
+
'ssl-verify' => true,
|
22
|
+
'file-protocol' => 'winrm'
|
23
|
+
}
|
12
24
|
end
|
13
25
|
|
14
26
|
def provided_features
|
@@ -26,6 +38,10 @@ module Bolt
|
|
26
38
|
raise Bolt::ValidationError, 'ssl option must be a Boolean true or false'
|
27
39
|
end
|
28
40
|
|
41
|
+
if ssl_flag && (options['file-protocol'] == 'smb')
|
42
|
+
raise Bolt::ValidationError, 'SMB file transfers are not allowed with SSL enabled'
|
43
|
+
end
|
44
|
+
|
29
45
|
ssl_verify_flag = options['ssl-verify']
|
30
46
|
unless !!ssl_verify_flag == ssl_verify_flag
|
31
47
|
raise Bolt::ValidationError, 'ssl-verify option must be a Boolean true or false'
|
@@ -135,7 +151,13 @@ module Bolt
|
|
135
151
|
if Powershell.powershell_file?(remote_task_path) && stdin.nil?
|
136
152
|
conn.execute(Powershell.run_ps_task(arguments, remote_task_path, input_method))
|
137
153
|
else
|
138
|
-
|
154
|
+
interpreter = select_interpreter(remote_task_path, target.options['interpreters'])
|
155
|
+
if interpreter
|
156
|
+
path = interpreter
|
157
|
+
args = [remote_task_path]
|
158
|
+
else
|
159
|
+
path, args = *Powershell.process_from_extension(remote_task_path)
|
160
|
+
end
|
139
161
|
conn.execute_process(path, args, stdin)
|
140
162
|
end
|
141
163
|
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'bolt/node/errors'
|
4
4
|
require 'bolt/node/output'
|
5
|
+
require 'ruby_smb'
|
5
6
|
|
6
7
|
module Bolt
|
7
8
|
module Transport
|
@@ -17,9 +18,9 @@ module Bolt
|
|
17
18
|
default_port = target.options['ssl'] ? HTTPS_PORT : HTTP_PORT
|
18
19
|
@port = @target.port || default_port
|
19
20
|
@user = @target.user
|
20
|
-
|
21
|
-
# Accept a single entry or a list, ensure each is prefixed with '.'
|
21
|
+
# Build set of extensions from extensions config as well as interpreters
|
22
22
|
extensions = [target.options['extensions'] || []].flatten.map { |ext| ext[0] != '.' ? '.' + ext : ext }
|
23
|
+
extensions += target.options['interpreters'].keys if target.options['interpreters']
|
23
24
|
@extensions = DEFAULT_EXTENSIONS.to_set.merge(extensions)
|
24
25
|
|
25
26
|
@logger = Logging.logger[@target.host]
|
@@ -93,6 +94,7 @@ module Bolt
|
|
93
94
|
|
94
95
|
def disconnect
|
95
96
|
@session&.close
|
97
|
+
@client&.disconnect!
|
96
98
|
@logger.debug { "Closed session" }
|
97
99
|
end
|
98
100
|
|
@@ -141,12 +143,47 @@ module Bolt
|
|
141
143
|
end
|
142
144
|
|
143
145
|
def write_remote_file(source, destination)
|
146
|
+
if target.options['file-protocol'] == 'smb'
|
147
|
+
write_remote_file_smb(source, destination)
|
148
|
+
else
|
149
|
+
write_remote_file_winrm(source, destination)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def write_remote_file_winrm(source, destination)
|
144
154
|
fs = ::WinRM::FS::FileManager.new(@connection)
|
145
155
|
fs.upload(source, destination)
|
146
156
|
rescue StandardError => e
|
147
157
|
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
148
158
|
end
|
149
159
|
|
160
|
+
def write_remote_file_smb(source, destination)
|
161
|
+
win_dest = destination.tr('/', '\\')
|
162
|
+
if (md = win_dest.match(/^([a-z]):\\(.*)/i))
|
163
|
+
# if drive, use admin share for that drive, so path is '\\host\C$'
|
164
|
+
path = "\\\\#{@target.host}\\#{md[1]}$"
|
165
|
+
dest = md[2]
|
166
|
+
elsif (md = win_dest.match(/^(\\\\[^\\]+\\[^\\]+)\\(.*)/))
|
167
|
+
# if unc, path is '\\host\share'
|
168
|
+
path = md[1]
|
169
|
+
dest = md[2]
|
170
|
+
else
|
171
|
+
raise ArgumentError, "Unknown destination '#{destination}'"
|
172
|
+
end
|
173
|
+
|
174
|
+
client = smb_client_login
|
175
|
+
tree = client.tree_connect(path)
|
176
|
+
begin
|
177
|
+
write_remote_file_smb_recursive(tree, source, dest)
|
178
|
+
ensure
|
179
|
+
tree.disconnect!
|
180
|
+
end
|
181
|
+
rescue ::RubySMB::Error::UnexpectedStatusCode => e
|
182
|
+
raise Bolt::Node::FileError.new("SMB Error: #{e.message}", 'WRITE_ERROR')
|
183
|
+
rescue StandardError => e
|
184
|
+
raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
|
185
|
+
end
|
186
|
+
|
150
187
|
def make_tempdir
|
151
188
|
find_parent = target.options['tmpdir'] ? "\"#{target.options['tmpdir']}\"" : '[System.IO.Path]::GetTempPath()'
|
152
189
|
result = execute(Powershell.make_tempdir(find_parent))
|
@@ -184,6 +221,79 @@ module Bolt
|
|
184
221
|
write_remote_file(content, remote_path)
|
185
222
|
remote_path
|
186
223
|
end
|
224
|
+
|
225
|
+
private
|
226
|
+
|
227
|
+
def smb_client_login
|
228
|
+
return @client if @client
|
229
|
+
|
230
|
+
dispatcher = RubySMB::Dispatcher::Socket.new(smb_socket_connect)
|
231
|
+
@client = RubySMB::Client.new(dispatcher, smb1: false, smb2: true, username: @user, password: target.password)
|
232
|
+
status = @client.login
|
233
|
+
case status
|
234
|
+
when WindowsError::NTStatus::STATUS_SUCCESS
|
235
|
+
@logger.debug { "Connected to #{@client.dns_host_name}" }
|
236
|
+
when WindowsError::NTStatus::STATUS_LOGON_FAILURE
|
237
|
+
raise Bolt::Node::ConnectError.new(
|
238
|
+
"SMB authentication failed for #{target.host}",
|
239
|
+
'AUTH_ERROR'
|
240
|
+
)
|
241
|
+
else
|
242
|
+
raise Bolt::Node::ConnectError.new(
|
243
|
+
"Failed to connect to #{target.host} using SMB: #{status.description}",
|
244
|
+
'CONNECT_ERROR'
|
245
|
+
)
|
246
|
+
end
|
247
|
+
|
248
|
+
@client
|
249
|
+
end
|
250
|
+
|
251
|
+
SMB_PORT = 445
|
252
|
+
|
253
|
+
def smb_socket_connect
|
254
|
+
# It's lame that TCPSocket doesn't take a connect timeout
|
255
|
+
# Using Timeout.timeout is bad, but is done elsewhere...
|
256
|
+
Timeout.timeout(target.options['connect-timeout']) do
|
257
|
+
TCPSocket.new(target.host, target.options['smb-port'] || SMB_PORT)
|
258
|
+
end
|
259
|
+
rescue Errno::ECONNREFUSED => e
|
260
|
+
# handle this to prevent obscuring error message as SMB problem
|
261
|
+
raise Bolt::Node::ConnectError.new(
|
262
|
+
"Failed to connect to #{target.host} using SMB: #{e.message}",
|
263
|
+
'CONNECT_ERROR'
|
264
|
+
)
|
265
|
+
rescue Timeout::Error
|
266
|
+
raise Bolt::Node::ConnectError.new(
|
267
|
+
"Timeout after #{target.options['connect-timeout']} seconds connecting to #{target.host}",
|
268
|
+
'CONNECT_ERROR'
|
269
|
+
)
|
270
|
+
end
|
271
|
+
|
272
|
+
def write_remote_file_smb_recursive(tree, source, dest)
|
273
|
+
if Dir.exist?(source)
|
274
|
+
tree.open_directory(directory: dest, write: true, disposition: ::RubySMB::Dispositions::FILE_OPEN_IF)
|
275
|
+
|
276
|
+
(Dir.entries(source) - ['.', '..']).each do |child|
|
277
|
+
child_dest = dest + '\\' + child
|
278
|
+
write_remote_file_smb_recursive(tree, File.join(source, child), child_dest)
|
279
|
+
end
|
280
|
+
return
|
281
|
+
end
|
282
|
+
|
283
|
+
file = tree.open_file(filename: dest, write: true, disposition: ::RubySMB::Dispositions::FILE_OVERWRITE_IF)
|
284
|
+
begin
|
285
|
+
# `file` doesn't derive from IO, so can't use IO.copy_stream
|
286
|
+
File.open(source, 'rb') do |f|
|
287
|
+
pos = 0
|
288
|
+
while (buf = f.read(8 * 1024 * 1024))
|
289
|
+
file.write(data: buf, offset: pos)
|
290
|
+
pos += buf.length
|
291
|
+
end
|
292
|
+
end
|
293
|
+
ensure
|
294
|
+
file.close
|
295
|
+
end
|
296
|
+
end
|
187
297
|
end
|
188
298
|
end
|
189
299
|
end
|
data/lib/bolt/version.rb
CHANGED
@@ -47,8 +47,22 @@
|
|
47
47
|
"extensions": {
|
48
48
|
"type": "array",
|
49
49
|
"description": "List of file extensions that are accepted for scripts or tasks"
|
50
|
+
},
|
51
|
+
"interpreters": {
|
52
|
+
"type": "object",
|
53
|
+
"description": "Map of file extensions to remote executable"
|
54
|
+
},
|
55
|
+
"file-protocol": {
|
56
|
+
"type": "string",
|
57
|
+
"enum": ["winrm", "smb"],
|
58
|
+
"description": "Protocol for file transfer, WinRM or SMB"
|
59
|
+
},
|
60
|
+
"smb-port": {
|
61
|
+
"type": "integer",
|
62
|
+
"description": "Port for SMB protocol"
|
50
63
|
}
|
51
64
|
},
|
65
|
+
|
52
66
|
"required": ["hostname", "user", "password"],
|
53
67
|
"additionalProperties": false
|
54
68
|
},
|
data/lib/bolt_spec/plans.rb
CHANGED
@@ -32,6 +32,11 @@ require 'bolt/pal'
|
|
32
32
|
#
|
33
33
|
# Configuration
|
34
34
|
#
|
35
|
+
# To configure Puppet and Bolt at the beginning of tests, add the following
|
36
|
+
# line to your spec_helper.rb:
|
37
|
+
#
|
38
|
+
# BoltSpec::Plans.init
|
39
|
+
#
|
35
40
|
# By default the plan helpers use the modulepath set up for rspec-puppet and
|
36
41
|
# an otherwise empty bolt config and inventory. To create your own values for
|
37
42
|
# these override the modulepath, config, or inventory methods.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-02-
|
11
|
+
date: 2019-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -184,6 +184,20 @@ dependencies:
|
|
184
184
|
- - "~>"
|
185
185
|
- !ruby/object:Gem::Version
|
186
186
|
version: '2.6'
|
187
|
+
- !ruby/object:Gem::Dependency
|
188
|
+
name: ruby_smb
|
189
|
+
requirement: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - "~>"
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '1.0'
|
194
|
+
type: :runtime
|
195
|
+
prerelease: false
|
196
|
+
version_requirements: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - "~>"
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '1.0'
|
187
201
|
- !ruby/object:Gem::Dependency
|
188
202
|
name: terminal-table
|
189
203
|
requirement: !ruby/object:Gem::Requirement
|
@@ -345,6 +359,7 @@ files:
|
|
345
359
|
- lib/bolt/outputter/human.rb
|
346
360
|
- lib/bolt/outputter/json.rb
|
347
361
|
- lib/bolt/pal.rb
|
362
|
+
- lib/bolt/pal/issues.rb
|
348
363
|
- lib/bolt/pal/logging.rb
|
349
364
|
- lib/bolt/plan_result.rb
|
350
365
|
- lib/bolt/puppetdb.rb
|