bolt 1.31.1 → 1.32.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/datatypes/target.rb +49 -16
- data/bolt-modules/boltlib/lib/puppet/functions/get_resources.rb +9 -2
- data/bolt-modules/boltlib/lib/puppet/functions/get_target.rb +36 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +42 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_config.rb +46 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_feature.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_var.rb +6 -2
- data/lib/bolt/analytics.rb +1 -1
- data/lib/bolt/apply_result.rb +23 -0
- data/lib/bolt/bolt_option_parser.rb +16 -0
- data/lib/bolt/boltdir.rb +3 -1
- data/lib/bolt/cli.rb +20 -6
- data/lib/bolt/config.rb +1 -3
- data/lib/bolt/inventory/group2.rb +40 -34
- data/lib/bolt/inventory/inventory2.rb +203 -134
- data/lib/bolt/inventory.rb +2 -3
- data/lib/bolt/pal/issues.rb +6 -0
- data/lib/bolt/pal.rb +29 -1
- data/lib/bolt/plugin.rb +2 -2
- data/lib/bolt/secret/base.rb +3 -1
- data/lib/bolt/target.rb +147 -0
- data/lib/bolt/task.rb +1 -1
- data/lib/bolt/transport/powershell.rb +12 -5
- data/lib/bolt/transport/winrm.rb +1 -2
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/schemas/action-run_script.json +4 -1
- data/lib/bolt_spec/plans/mock_executor.rb +17 -0
- data/lib/bolt_spec/plans/publish_stub.rb +49 -0
- data/lib/bolt_spec/plans.rb +18 -1
- data/lib/bolt_spec/run.rb +5 -2
- data/lib/plan_executor/app.rb +1 -1
- metadata +5 -2
data/lib/bolt/target.rb
CHANGED
@@ -1,8 +1,154 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'bolt/error'
|
4
|
+
require 'bolt/util'
|
4
5
|
|
5
6
|
module Bolt
|
7
|
+
class Target2
|
8
|
+
attr_accessor :inventory
|
9
|
+
|
10
|
+
# Target.new from a plan initialized with a hash
|
11
|
+
def self.from_asserted_hash(hash)
|
12
|
+
inventory = Puppet.lookup(:bolt_inventory)
|
13
|
+
inventory.create_target_from_plan(hash)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Target.new from a plan with just a uri
|
17
|
+
# rubocop:disable UnusedMethodArgument
|
18
|
+
def self.from_asserted_args(uri = nil,
|
19
|
+
name = nil,
|
20
|
+
target_alias = nil,
|
21
|
+
config = nil,
|
22
|
+
facts = nil,
|
23
|
+
vars = nil,
|
24
|
+
features = nil,
|
25
|
+
plugin_hooks = nil)
|
26
|
+
inventory = Puppet.lookup(:bolt_inventory)
|
27
|
+
inventory.create_target_from_plan('uri' => uri)
|
28
|
+
end
|
29
|
+
|
30
|
+
# URI can be passes as nil
|
31
|
+
def initialize(uri = nil,
|
32
|
+
name = nil,
|
33
|
+
target_alias = nil,
|
34
|
+
config = nil,
|
35
|
+
facts = nil,
|
36
|
+
vars = nil,
|
37
|
+
features = nil,
|
38
|
+
plugin_hooks = nil)
|
39
|
+
@name = name
|
40
|
+
end
|
41
|
+
# rubocop:enable UnusedMethodArgument
|
42
|
+
|
43
|
+
# Used for munging target + group data
|
44
|
+
def target_data_hash
|
45
|
+
{
|
46
|
+
'config' => @inventory.targets[@name]['config'],
|
47
|
+
'vars' => @inventory.targets[@name]['vars'],
|
48
|
+
'facts' => @inventory.targets[@name]['facts'],
|
49
|
+
'features' => @inventory.targets[@name]['features'].to_a,
|
50
|
+
'plugin_hooks' => @inventory.targets[@name]['plugin_hooks'],
|
51
|
+
'name' => @inventory.targets[@name]['name'],
|
52
|
+
'uri' => @inventory.targets[@name]['uri'],
|
53
|
+
'alias' => @inventory.targets[@name]['target_alias']
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
# features returns an array to be compatible with plans
|
58
|
+
def features
|
59
|
+
@inventory.features(self).to_a
|
60
|
+
end
|
61
|
+
|
62
|
+
# Use feature_set internally to access set
|
63
|
+
def feature_set
|
64
|
+
@inventory.features(self)
|
65
|
+
end
|
66
|
+
|
67
|
+
def vars
|
68
|
+
@inventory.vars(self)
|
69
|
+
end
|
70
|
+
|
71
|
+
def facts
|
72
|
+
@inventory.facts(self)
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_s
|
76
|
+
safe_name
|
77
|
+
end
|
78
|
+
|
79
|
+
def config
|
80
|
+
@inventory.target_config(self)
|
81
|
+
end
|
82
|
+
|
83
|
+
def safe_name
|
84
|
+
@inventory.targets[@name]['safe_name']
|
85
|
+
end
|
86
|
+
|
87
|
+
def target_alias
|
88
|
+
@inventory.targets[@name]['target_alias']
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_h
|
92
|
+
options.merge(
|
93
|
+
'name' => name,
|
94
|
+
'uri' => uri,
|
95
|
+
'protocol' => protocol,
|
96
|
+
'user' => user,
|
97
|
+
'password' => password,
|
98
|
+
'host' => host,
|
99
|
+
'port' => port
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
def host
|
104
|
+
@inventory.targets[@name]['uri_obj']&.hostname || @inventory.targets[@name]['host']
|
105
|
+
end
|
106
|
+
|
107
|
+
attr_reader :name
|
108
|
+
|
109
|
+
def uri
|
110
|
+
@inventory.targets[@name]['uri']
|
111
|
+
end
|
112
|
+
|
113
|
+
def remote?
|
114
|
+
@inventory.targets[@name]['uri_obj']&.scheme == 'remote' || @inventory.targets[@name]['protocol'] == 'remote'
|
115
|
+
end
|
116
|
+
|
117
|
+
def port
|
118
|
+
@inventory.targets[@name]['uri_obj']&.port || @inventory.targets[@name]['port']
|
119
|
+
end
|
120
|
+
|
121
|
+
# transport is separate from protocol for remote targets.
|
122
|
+
def transport
|
123
|
+
remote? ? 'remote' : protocol
|
124
|
+
end
|
125
|
+
|
126
|
+
def protocol
|
127
|
+
@inventory.targets[@name]['uri_obj']&.scheme || @inventory.targets[@name]['protocol']
|
128
|
+
end
|
129
|
+
|
130
|
+
def user
|
131
|
+
unencode(@inventory.targets[@name]['uri_obj']&.user) || @inventory.targets[@name]['user']
|
132
|
+
end
|
133
|
+
|
134
|
+
def password
|
135
|
+
unencode(@inventory.targets[@name]['uri_obj']&.password) || @inventory.targets[@name]['password']
|
136
|
+
end
|
137
|
+
|
138
|
+
def options
|
139
|
+
@inventory.targets[@name]['options']
|
140
|
+
end
|
141
|
+
|
142
|
+
def plugin_hooks
|
143
|
+
@inventory.targets[@name]['cached_state']['plugin_hooks']
|
144
|
+
end
|
145
|
+
|
146
|
+
def unencode(component)
|
147
|
+
Addressable::URI.unencode_component(component)
|
148
|
+
end
|
149
|
+
private :unencode
|
150
|
+
end
|
151
|
+
|
6
152
|
class Target
|
7
153
|
attr_reader :options
|
8
154
|
# CODEREVIEW: this feels wrong. The altertative is threading inventory through the
|
@@ -87,6 +233,7 @@ module Bolt
|
|
87
233
|
Set.new
|
88
234
|
end
|
89
235
|
end
|
236
|
+
alias feature_set features
|
90
237
|
|
91
238
|
def plugin_hooks
|
92
239
|
if @inventory
|
data/lib/bolt/task.rb
CHANGED
@@ -73,7 +73,7 @@ module Bolt
|
|
73
73
|
# and any additional files (name and path)
|
74
74
|
def select_implementation(target, provided_features = [])
|
75
75
|
impl = if (impls = implementations)
|
76
|
-
available_features = target.
|
76
|
+
available_features = target.feature_set + provided_features
|
77
77
|
impl = impls.find do |imp|
|
78
78
|
remote_impl = imp['remote']
|
79
79
|
remote_impl = metadata['remote'] if remote_impl.nil?
|
@@ -52,16 +52,23 @@ module Bolt
|
|
52
52
|
"[Environment]::SetEnvironmentVariable('#{arg}', @'\n#{val}\n'@)"
|
53
53
|
end
|
54
54
|
|
55
|
+
def quote_string(string)
|
56
|
+
"'" + string.gsub("'", "''") + "'"
|
57
|
+
end
|
58
|
+
|
55
59
|
def execute_process(path, arguments, stdin = nil)
|
56
|
-
quoted_args = arguments.map
|
57
|
-
"'" + arg.gsub("'", "''") + "'"
|
58
|
-
end.join(' ')
|
60
|
+
quoted_args = arguments.map { |arg| quote_string(arg) }.join(' ')
|
59
61
|
|
62
|
+
quoted_path = if path =~ /^'.*'$/ || path =~ /^".*"$/
|
63
|
+
path
|
64
|
+
else
|
65
|
+
quote_string(path)
|
66
|
+
end
|
60
67
|
exec_cmd =
|
61
68
|
if stdin.nil?
|
62
|
-
"& #{
|
69
|
+
"& #{quoted_path} #{quoted_args}"
|
63
70
|
else
|
64
|
-
"@'\n#{stdin}\n'@ | & #{
|
71
|
+
"@'\n#{stdin}\n'@ | & #{quoted_path} #{quoted_args}"
|
65
72
|
end
|
66
73
|
<<-PS
|
67
74
|
$OutputEncoding = [Console]::OutputEncoding
|
data/lib/bolt/transport/winrm.rb
CHANGED
@@ -163,8 +163,7 @@ module Bolt
|
|
163
163
|
if Powershell.powershell_file?(remote_task_path) && stdin.nil?
|
164
164
|
conn.execute(Powershell.run_ps_task(arguments, remote_task_path, input_method))
|
165
165
|
else
|
166
|
-
interpreter = select_interpreter(remote_task_path, target.options['interpreters'])
|
167
|
-
if interpreter
|
166
|
+
if (interpreter = select_interpreter(remote_task_path, target.options['interpreters']))
|
168
167
|
path = interpreter
|
169
168
|
args = [remote_task_path]
|
170
169
|
else
|
data/lib/bolt/version.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'bolt_spec/plans/action_stubs'
|
4
|
+
require 'bolt_spec/plans/publish_stub'
|
4
5
|
require 'bolt/error'
|
5
6
|
require 'bolt/result_set'
|
6
7
|
require 'bolt/result'
|
@@ -25,6 +26,7 @@ module BoltSpec
|
|
25
26
|
@allow_apply = false
|
26
27
|
@modulepath = [modulepath].flatten.map { |path| File.absolute_path(path) }
|
27
28
|
MOCKED_ACTIONS.each { |action| instance_variable_set(:"@#{action}_doubles", {}) }
|
29
|
+
@stub_out_message = nil
|
28
30
|
end
|
29
31
|
|
30
32
|
def module_file_id(file)
|
@@ -99,6 +101,7 @@ module BoltSpec
|
|
99
101
|
doub.assert_called(object)
|
100
102
|
end
|
101
103
|
end
|
104
|
+
@stub_out_message.assert_called('out::message') if @stub_out_message
|
102
105
|
end
|
103
106
|
|
104
107
|
MOCKED_ACTIONS.each do |action|
|
@@ -107,6 +110,10 @@ module BoltSpec
|
|
107
110
|
end
|
108
111
|
end
|
109
112
|
|
113
|
+
def stub_out_message
|
114
|
+
@stub_out_message ||= ActionDouble.new(:PublishStub)
|
115
|
+
end
|
116
|
+
|
110
117
|
def stub_apply
|
111
118
|
@allow_apply = true
|
112
119
|
end
|
@@ -133,6 +140,16 @@ module BoltSpec
|
|
133
140
|
|
134
141
|
def report_apply(_statements, _resources); end
|
135
142
|
|
143
|
+
def publish_event(event)
|
144
|
+
if event[:type] == :message
|
145
|
+
unless @stub_out_message
|
146
|
+
@error_message = "Unexpected call to 'out::message(#{event[:message]})'"
|
147
|
+
raise UnexpectedInvocation, @error_message
|
148
|
+
end
|
149
|
+
@stub_out_message.process(event[:message])
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
136
153
|
# Mocked for Apply so it does not compile and execute.
|
137
154
|
def with_node_logging(_description, targets)
|
138
155
|
raise "Unexpected call to apply(#{targets})" unless @allow_apply
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/result'
|
4
|
+
require 'bolt/util'
|
5
|
+
|
6
|
+
module BoltSpec
|
7
|
+
module Plans
|
8
|
+
class PublishStub < ActionStub
|
9
|
+
def return
|
10
|
+
raise "return is not implemented for out_message"
|
11
|
+
end
|
12
|
+
|
13
|
+
def return_for_targets(_data)
|
14
|
+
raise "return_for_targets is not implemented for out_message"
|
15
|
+
end
|
16
|
+
|
17
|
+
def always_return(_data)
|
18
|
+
raise "always_return is not implemented for out_message"
|
19
|
+
end
|
20
|
+
|
21
|
+
def error_with(_data)
|
22
|
+
raise "error_with is not implemented for out_message"
|
23
|
+
end
|
24
|
+
|
25
|
+
def matches(message)
|
26
|
+
if @invocation[:options] && message != @invocation[:options]
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
def call(_event)
|
34
|
+
@calls += 1
|
35
|
+
end
|
36
|
+
|
37
|
+
def parameters
|
38
|
+
@invocation[:options]
|
39
|
+
end
|
40
|
+
|
41
|
+
# Public methods
|
42
|
+
|
43
|
+
def with_params(params)
|
44
|
+
@invocation[:options] = params
|
45
|
+
self
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/bolt_spec/plans.rb
CHANGED
@@ -63,6 +63,8 @@ require 'bolt/pal'
|
|
63
63
|
# - allow_upload(file), expect_upload(file): expect the identified source file
|
64
64
|
# - allow_apply_prep: allows `apply_prep` to be invoked in the plan but does not allow modifiers
|
65
65
|
# - allow_apply: allows `apply` to be invoked in the plan but does not allow modifiers
|
66
|
+
# - allow_out_message, expect_out_message: expect a message to be passed to out::message (only modifiers are
|
67
|
+
# be_called_times(n), with_params(params), and not_be_called)
|
66
68
|
#
|
67
69
|
# Stub modifiers:
|
68
70
|
# - be_called_times(n): if allowed, fail if the action is called more than 'n' times
|
@@ -128,6 +130,12 @@ require 'bolt/pal'
|
|
128
130
|
# end
|
129
131
|
# expect(run_plan('my_plan', { 'param1' => 10 })).to eq(10)
|
130
132
|
# end
|
133
|
+
|
134
|
+
# it 'expects multiple messages to out::message' do
|
135
|
+
# expect_out_message.be_called_times(2).with_params(message)
|
136
|
+
# result = run_plan(plan_name, 'messages' => [message, message])
|
137
|
+
# expect(result).to be_ok
|
138
|
+
# end
|
131
139
|
# end
|
132
140
|
#
|
133
141
|
# See spec/bolt_spec/plan_spec.rb for more examples.
|
@@ -172,7 +180,7 @@ module BoltSpec
|
|
172
180
|
end
|
173
181
|
|
174
182
|
def run_plan(name, params)
|
175
|
-
pal = Bolt::PAL.new(config.modulepath, config.hiera_config)
|
183
|
+
pal = Bolt::PAL.new(config.modulepath, config.hiera_config, config.boltdir.resource_types)
|
176
184
|
result = pal.run_plan(name, params, executor, inventory, puppetdb_client)
|
177
185
|
|
178
186
|
if executor.error_message
|
@@ -221,6 +229,15 @@ module BoltSpec
|
|
221
229
|
nil
|
222
230
|
end
|
223
231
|
|
232
|
+
def allow_out_message
|
233
|
+
executor.stub_out_message.add_stub
|
234
|
+
end
|
235
|
+
alias allow_any_out_message allow_out_message
|
236
|
+
|
237
|
+
def expect_out_message
|
238
|
+
allow_out_message.expect_call
|
239
|
+
end
|
240
|
+
|
224
241
|
# Example helpers to mock other run functions
|
225
242
|
# The with_targets method makes sense for all stubs
|
226
243
|
# with_params could be reused for options
|
data/lib/bolt_spec/run.rb
CHANGED
@@ -110,7 +110,7 @@ module BoltSpec
|
|
110
110
|
else
|
111
111
|
begin
|
112
112
|
unless File.stat(manifest).readable?
|
113
|
-
raise
|
113
|
+
raise Bolt::FileError.new("The manifest '#{manifest}' is unreadable", manifest)
|
114
114
|
end
|
115
115
|
rescue Errno::ENOENT
|
116
116
|
raise Bolt::FileError.new("The manifest '#{manifest}' does not exist", manifest)
|
@@ -152,7 +152,10 @@ module BoltSpec
|
|
152
152
|
end
|
153
153
|
|
154
154
|
def pal
|
155
|
-
@pal ||= Bolt::PAL.new(config.modulepath,
|
155
|
+
@pal ||= Bolt::PAL.new(config.modulepath,
|
156
|
+
config.hiera_config,
|
157
|
+
config.boltdir.resource_types,
|
158
|
+
config.compile_concurrency)
|
156
159
|
end
|
157
160
|
|
158
161
|
def resolve_targets(target_spec)
|
data/lib/plan_executor/app.rb
CHANGED
@@ -39,7 +39,7 @@ module PlanExecutor
|
|
39
39
|
# functional will be making changes to Puppet that remove the need for
|
40
40
|
# global Puppet state.
|
41
41
|
# https://github.com/puppetlabs/bolt/blob/master/lib/bolt/pal.rb#L166
|
42
|
-
@pal = Bolt::PAL.new(config['modulepath'], nil)
|
42
|
+
@pal = Bolt::PAL.new(config['modulepath'], nil, nil)
|
43
43
|
|
44
44
|
@schema = JSON.parse(File.read(File.join(__dir__, 'schemas', 'run_plan.json')))
|
45
45
|
@worker = Concurrent::SingleThreadExecutor.new
|
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.32.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-
|
11
|
+
date: 2019-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -330,6 +330,7 @@ files:
|
|
330
330
|
- bolt-modules/boltlib/lib/puppet/functions/facts.rb
|
331
331
|
- bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb
|
332
332
|
- bolt-modules/boltlib/lib/puppet/functions/get_resources.rb
|
333
|
+
- bolt-modules/boltlib/lib/puppet/functions/get_target.rb
|
333
334
|
- bolt-modules/boltlib/lib/puppet/functions/get_targets.rb
|
334
335
|
- bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb
|
335
336
|
- bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb
|
@@ -337,6 +338,7 @@ files:
|
|
337
338
|
- bolt-modules/boltlib/lib/puppet/functions/run_plan.rb
|
338
339
|
- bolt-modules/boltlib/lib/puppet/functions/run_script.rb
|
339
340
|
- bolt-modules/boltlib/lib/puppet/functions/run_task.rb
|
341
|
+
- bolt-modules/boltlib/lib/puppet/functions/set_config.rb
|
340
342
|
- bolt-modules/boltlib/lib/puppet/functions/set_feature.rb
|
341
343
|
- bolt-modules/boltlib/lib/puppet/functions/set_var.rb
|
342
344
|
- bolt-modules/boltlib/lib/puppet/functions/upload_file.rb
|
@@ -463,6 +465,7 @@ files:
|
|
463
465
|
- lib/bolt_spec/plans/action_stubs/task_stub.rb
|
464
466
|
- lib/bolt_spec/plans/action_stubs/upload_stub.rb
|
465
467
|
- lib/bolt_spec/plans/mock_executor.rb
|
468
|
+
- lib/bolt_spec/plans/publish_stub.rb
|
466
469
|
- lib/bolt_spec/run.rb
|
467
470
|
- lib/logging_extensions/logging.rb
|
468
471
|
- lib/plan_executor/app.rb
|