bolt 1.25.0 → 1.26.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/lib/bolt/bolt_option_parser.rb +16 -1
- data/lib/bolt/cli.rb +12 -1
- data/lib/bolt/config.rb +22 -0
- data/lib/bolt/inventory/group2.rb +11 -2
- data/lib/bolt/logger.rb +1 -1
- data/lib/bolt/outputter/human.rb +7 -0
- data/lib/bolt/outputter/json.rb +7 -0
- data/lib/bolt/pal.rb +6 -2
- data/lib/bolt/pal/yaml_plan.rb +10 -7
- data/lib/bolt/pal/yaml_plan/evaluator.rb +51 -16
- data/lib/bolt/pal/yaml_plan/step.rb +70 -122
- data/lib/bolt/pal/yaml_plan/step/command.rb +37 -0
- data/lib/bolt/pal/yaml_plan/step/eval.rb +42 -0
- data/lib/bolt/pal/yaml_plan/step/plan.rb +38 -0
- data/lib/bolt/pal/yaml_plan/step/resources.rb +102 -0
- data/lib/bolt/pal/yaml_plan/step/script.rb +43 -0
- data/lib/bolt/pal/yaml_plan/step/task.rb +39 -0
- data/lib/bolt/pal/yaml_plan/step/upload.rb +38 -0
- data/lib/bolt/pal/yaml_plan/transpiler.rb +1 -2
- data/lib/bolt/plugin.rb +9 -0
- data/lib/bolt/plugin/task.rb +91 -0
- data/lib/bolt/transport/orch.rb +1 -1
- data/lib/bolt/transport/orch/connection.rb +1 -1
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/transport_app.rb +11 -9
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2431380225c5f60abf51caa85cfa1ee3aeadcf1ef494192e93bfb8f7e175d7f9
|
4
|
+
data.tar.gz: a49aa9489c0992bcaab219b54fe054dd3ef8d078231cf64ed7e039c8c580bb46
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a28ce31a001a91307ce8e31cf4307a7eac3f5027143444eae22a49e406820e808bdffa668a9daad5b52bec76413af55a28c50b2aa439d4516951370d7f15210
|
7
|
+
data.tar.gz: fa64ecb34705bb81e728ce9067928bcde35b51630d672d8666d09766f941c26811466608f03927852061a5848135b7ee2d6725224770f0a743404a6e8840422f
|
@@ -28,6 +28,9 @@ module Bolt
|
|
28
28
|
when 'file'
|
29
29
|
{ flags: ACTION_OPTS + %w[tmpdir],
|
30
30
|
banner: FILE_HELP }
|
31
|
+
when 'inventory'
|
32
|
+
{ flags: OPTIONS[:inventory] + OPTIONS[:global] + %w[format inventoryfile boltdir configfile],
|
33
|
+
banner: INVENTORY_HELP }
|
31
34
|
when 'plan'
|
32
35
|
case action
|
33
36
|
when 'convert'
|
@@ -110,6 +113,7 @@ Available subcommands:
|
|
110
113
|
bolt secret createkeys Create new encryption keys
|
111
114
|
bolt secret encrypt <plaintext> Encrypt a value
|
112
115
|
bolt secret decrypt <encrypted> Decrypt a value
|
116
|
+
bolt inventory show Show the list of targets an action would run on
|
113
117
|
|
114
118
|
Run `bolt <subcommand> --help` to view specific examples.
|
115
119
|
|
@@ -263,9 +267,19 @@ Available options are:
|
|
263
267
|
createkeys Create new encryption keys
|
264
268
|
encrypt Encrypt a value
|
265
269
|
decrypt Decrypt a value
|
270
|
+
|
266
271
|
Available options are:
|
267
272
|
SECRET_HELP
|
268
273
|
|
274
|
+
INVENTORY_HELP = <<~INVENTORY_HELP
|
275
|
+
Usage: bolt inventory <action>
|
276
|
+
|
277
|
+
Available actions are:
|
278
|
+
show Show the list of targets an action would run on
|
279
|
+
|
280
|
+
Available options are:
|
281
|
+
INVENTORY_HELP
|
282
|
+
|
269
283
|
def initialize(options)
|
270
284
|
super()
|
271
285
|
|
@@ -366,7 +380,8 @@ Available options are:
|
|
366
380
|
@options[:'compile-concurrency'] = concurrency
|
367
381
|
end
|
368
382
|
define('-m', '--modulepath MODULES',
|
369
|
-
"List of directories containing modules, separated by '#{File::PATH_SEPARATOR}'"
|
383
|
+
"List of directories containing modules, separated by '#{File::PATH_SEPARATOR}'",
|
384
|
+
'Directories are case-sensitive') do |modulepath|
|
370
385
|
# When specified from the CLI, modulepath entries are relative to pwd
|
371
386
|
@options[:modulepath] = modulepath.split(File::PATH_SEPARATOR).map do |moduledir|
|
372
387
|
File.expand_path(moduledir)
|
data/lib/bolt/cli.rb
CHANGED
@@ -35,6 +35,7 @@ module Bolt
|
|
35
35
|
'file' => %w[upload],
|
36
36
|
'puppetfile' => %w[install show-modules],
|
37
37
|
'secret' => %w[encrypt decrypt createkeys],
|
38
|
+
'inventory' => %w[show],
|
38
39
|
'apply' => %w[] }.freeze
|
39
40
|
|
40
41
|
attr_reader :config, :options
|
@@ -117,6 +118,9 @@ module Bolt
|
|
117
118
|
|
118
119
|
Bolt::Logger.configure(config.log, config.color)
|
119
120
|
|
121
|
+
# Logger must be configured before checking path case, otherwise warnings will not display
|
122
|
+
@config.check_path_case('modulepath', @config.modulepath)
|
123
|
+
|
120
124
|
# After validation, initialize inventory and targets. Errors here are better to catch early.
|
121
125
|
# After this step
|
122
126
|
# options[:target_args] will contain a string/array version of the targetting options this is passed to plans
|
@@ -136,7 +140,7 @@ module Bolt
|
|
136
140
|
|
137
141
|
options
|
138
142
|
rescue Bolt::Error => e
|
139
|
-
|
143
|
+
outputter.fatal_error(e)
|
140
144
|
raise e
|
141
145
|
end
|
142
146
|
|
@@ -296,6 +300,8 @@ module Bolt
|
|
296
300
|
else
|
297
301
|
list_plans
|
298
302
|
end
|
303
|
+
elsif options[:subcommand] == 'inventory'
|
304
|
+
list_targets
|
299
305
|
end
|
300
306
|
return 0
|
301
307
|
elsif options[:action] == 'show-modules'
|
@@ -393,6 +399,11 @@ module Bolt
|
|
393
399
|
outputter.print_plans(pal.list_plans, pal.list_modulepath)
|
394
400
|
end
|
395
401
|
|
402
|
+
def list_targets
|
403
|
+
update_targets(options)
|
404
|
+
outputter.print_targets(options)
|
405
|
+
end
|
406
|
+
|
396
407
|
def run_plan(plan_name, plan_arguments, nodes, options)
|
397
408
|
unless nodes.empty?
|
398
409
|
if plan_arguments['nodes']
|
data/lib/bolt/config.rb
CHANGED
@@ -286,5 +286,27 @@ module Bolt
|
|
286
286
|
impl.validate(@transports[transport])
|
287
287
|
end
|
288
288
|
end
|
289
|
+
|
290
|
+
# Check if there is a case-insensitive match to the path
|
291
|
+
def check_path_case(type, paths)
|
292
|
+
return if paths.nil?
|
293
|
+
matches = matching_paths(paths)
|
294
|
+
|
295
|
+
if matches.any?
|
296
|
+
msg = "WARNING: Bolt is case sensitive when specifying a #{type}. Did you mean:\n"
|
297
|
+
matches.each { |path| msg += " #{path}\n" }
|
298
|
+
@logger.warn msg
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def matching_paths(paths)
|
303
|
+
[*paths].map { |p| Dir.glob([p, casefold(p)]) }.flatten.uniq.reject { |p| [*paths].include?(p) }
|
304
|
+
end
|
305
|
+
|
306
|
+
def casefold(path)
|
307
|
+
path.chars.map do |l|
|
308
|
+
l =~ /[A-Za-z]/ ? "[#{l.upcase}#{l.downcase}]" : l
|
309
|
+
end.join
|
310
|
+
end
|
289
311
|
end
|
290
312
|
end
|
@@ -106,7 +106,11 @@ module Bolt
|
|
106
106
|
end
|
107
107
|
plugin.validate_inventory_config(value) if plugin.respond_to?(:validate_inventory_config)
|
108
108
|
Concurrent::Delay.new do
|
109
|
-
|
109
|
+
begin
|
110
|
+
plugin.inventory_config(value)
|
111
|
+
rescue StandardError => e
|
112
|
+
raise Bolt::Plugin::PluginError.new(e.message, plugin, "inventory_targets in #{@name}")
|
113
|
+
end
|
110
114
|
end
|
111
115
|
else
|
112
116
|
value
|
@@ -203,7 +207,12 @@ module Bolt
|
|
203
207
|
raise ValidationError.new("#{plugin.name} does not support inventory_targets.", @name)
|
204
208
|
end
|
205
209
|
|
206
|
-
|
210
|
+
begin
|
211
|
+
targets = plugin.inventory_targets(lookup)
|
212
|
+
rescue StandardError => e
|
213
|
+
raise Bolt::Plugin::PluginError.new(e.message, plugin, "inventory_targets in #{@name}")
|
214
|
+
end
|
215
|
+
|
207
216
|
targets.each { |target| add_target(target) }
|
208
217
|
end
|
209
218
|
|
data/lib/bolt/logger.rb
CHANGED
data/lib/bolt/outputter/human.rb
CHANGED
@@ -311,6 +311,13 @@ module Bolt
|
|
311
311
|
end
|
312
312
|
end
|
313
313
|
|
314
|
+
def print_targets(options)
|
315
|
+
targets = options[:targets].map(&:name)
|
316
|
+
count = "#{targets.count} target#{'s' unless targets.count == 1}"
|
317
|
+
@stream.puts targets.join("\n")
|
318
|
+
@stream.puts colorize(:green, count)
|
319
|
+
end
|
320
|
+
|
314
321
|
# @param [Bolt::ResultSet] apply_result A ResultSet object representing the result of a `bolt apply`
|
315
322
|
def print_apply_result(apply_result, elapsed_time)
|
316
323
|
print_summary(apply_result, elapsed_time)
|
data/lib/bolt/outputter/json.rb
CHANGED
@@ -87,6 +87,13 @@ module Bolt
|
|
87
87
|
"moduledir": moduledir }.to_json)
|
88
88
|
end
|
89
89
|
|
90
|
+
def print_targets(options)
|
91
|
+
targets = options[:targets].map(&:name)
|
92
|
+
count = targets.count
|
93
|
+
@stream.puts({ "targets": targets,
|
94
|
+
"count": count }.to_json)
|
95
|
+
end
|
96
|
+
|
90
97
|
def fatal_error(err)
|
91
98
|
@stream.puts "],\n" if @items_open
|
92
99
|
@stream.puts '"_error": ' if @object_open
|
data/lib/bolt/pal.rb
CHANGED
@@ -240,10 +240,14 @@ module Bolt
|
|
240
240
|
end
|
241
241
|
end
|
242
242
|
|
243
|
-
def
|
244
|
-
|
243
|
+
def task_signature(task_name)
|
244
|
+
in_bolt_compiler do |compiler|
|
245
245
|
compiler.task_signature(task_name)
|
246
246
|
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def get_task_info(task_name)
|
250
|
+
task = task_signature(task_name)
|
247
251
|
|
248
252
|
if task.nil?
|
249
253
|
raise Bolt::Error.new(Bolt::Error.unknown_task(task_name), 'bolt/unknown-task')
|
data/lib/bolt/pal/yaml_plan.rb
CHANGED
@@ -48,19 +48,18 @@ module Bolt
|
|
48
48
|
stringified_step = Bolt::Util.walk_keys(step) { |key| stringify(key) }
|
49
49
|
stringified_step['name'] = stringify(stringified_step['name']) if stringified_step.key?('name')
|
50
50
|
|
51
|
-
step = Step.
|
52
|
-
|
53
|
-
duplicate_check(used_names, step)
|
51
|
+
step = Step.create(stringified_step, index + 1)
|
52
|
+
duplicate_check(used_names, stringified_step['name'], index + 1)
|
54
53
|
used_names << stringified_step['name'] if stringified_step['name']
|
55
54
|
step
|
56
55
|
end.freeze
|
57
56
|
@return = plan['return']
|
58
57
|
end
|
59
58
|
|
60
|
-
def duplicate_check(used_names,
|
61
|
-
if used_names.include?(
|
62
|
-
error_message = "Duplicate step name or parameter detected: #{
|
63
|
-
err =
|
59
|
+
def duplicate_check(used_names, name, step_number)
|
60
|
+
if used_names.include?(name)
|
61
|
+
error_message = "Duplicate step name or parameter detected: #{name.inspect}"
|
62
|
+
err = Step.step_error(error_message, name, step_number)
|
64
63
|
raise Bolt::Error.new(err, "bolt/invalid-plan")
|
65
64
|
end
|
66
65
|
end
|
@@ -102,6 +101,10 @@ module Bolt
|
|
102
101
|
def initialize(value)
|
103
102
|
@value = value
|
104
103
|
end
|
104
|
+
|
105
|
+
def ==(other)
|
106
|
+
self.class == other.class && @value == other.value
|
107
|
+
end
|
105
108
|
end
|
106
109
|
|
107
110
|
# This class represents a double-quoted YAML string, which is interpreted
|
@@ -13,23 +13,13 @@ module Bolt
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def dispatch_step(scope, step)
|
16
|
-
step_type = step.type
|
17
16
|
step_body = evaluate_code_blocks(scope, step.body)
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
when 'plan'
|
25
|
-
plan_step(scope, step_body)
|
26
|
-
when 'script'
|
27
|
-
script_step(scope, step_body)
|
28
|
-
when 'source'
|
29
|
-
upload_file_step(scope, step_body)
|
30
|
-
when 'eval'
|
31
|
-
eval_step(scope, step_body)
|
32
|
-
end
|
18
|
+
# Dispatch based on the step class name
|
19
|
+
step_type = step.class.name.split('::').last.downcase
|
20
|
+
method = "#{step_type}_step"
|
21
|
+
|
22
|
+
send(method, scope, step_body)
|
33
23
|
end
|
34
24
|
|
35
25
|
def task_step(scope, step)
|
@@ -82,7 +72,7 @@ module Bolt
|
|
82
72
|
scope.call_function('run_command', args)
|
83
73
|
end
|
84
74
|
|
85
|
-
def
|
75
|
+
def upload_step(scope, step)
|
86
76
|
source = step['source']
|
87
77
|
destination = step['destination']
|
88
78
|
target = step['target']
|
@@ -97,6 +87,51 @@ module Bolt
|
|
97
87
|
step['eval']
|
98
88
|
end
|
99
89
|
|
90
|
+
def resources_step(scope, step)
|
91
|
+
manifest = generate_manifest(step['resources'])
|
92
|
+
|
93
|
+
apply_manifest(scope, step['target'], manifest)
|
94
|
+
end
|
95
|
+
|
96
|
+
def generate_manifest(resources)
|
97
|
+
# inspect returns the Ruby representation of the resource hashes,
|
98
|
+
# which happens to be the same as the Puppet representation
|
99
|
+
puppet_resources = resources.inspect
|
100
|
+
|
101
|
+
# Because the :tasks setting globally controls which mode the parser
|
102
|
+
# is in, we need to make this snippet of non-tasks manifest code
|
103
|
+
# parseable in tasks mode. The way to do that is by putting it in an
|
104
|
+
# apply statement and taking the body.
|
105
|
+
<<~MANIFEST
|
106
|
+
apply('placeholder') {
|
107
|
+
$resources = #{puppet_resources}
|
108
|
+
$resources.each |$res| {
|
109
|
+
Resource[$res['type']] { $res['title']:
|
110
|
+
* => $res['parameters'],
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
# Add relationships if there is more than one resource
|
115
|
+
if $resources.length > 1 {
|
116
|
+
($resources.length - 1).each |$index| {
|
117
|
+
$lhs = $resources[$index]
|
118
|
+
$rhs = $resources[$index+1]
|
119
|
+
$lhs_resource = Resource[$lhs['type'] , $lhs['title']]
|
120
|
+
$rhs_resource = Resource[$rhs['type'] , $rhs['title']]
|
121
|
+
$lhs_resource -> $rhs_resource
|
122
|
+
}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
MANIFEST
|
126
|
+
end
|
127
|
+
|
128
|
+
def apply_manifest(scope, target, manifest)
|
129
|
+
ast = @evaluator.parse_string(manifest)
|
130
|
+
apply_block = ast.body.body
|
131
|
+
applicator = Puppet.lookup(:apply_executor)
|
132
|
+
applicator.apply([target], apply_block, scope)
|
133
|
+
end
|
134
|
+
|
100
135
|
# This is the method that Puppet calls to evaluate the plan. The name
|
101
136
|
# makes more sense for .pp plans.
|
102
137
|
def evaluate_block_with_bindings(closure_scope, args_hash, plan)
|
@@ -8,152 +8,89 @@ module Bolt
|
|
8
8
|
class Step
|
9
9
|
attr_reader :name, :type, :body, :target
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
'command' => {
|
14
|
-
'allowed_keys' => Set['command'].merge(COMMON_STEP_KEYS),
|
15
|
-
'required_keys' => Set['target']
|
16
|
-
},
|
17
|
-
'script' => {
|
18
|
-
'allowed_keys' => Set['script', 'parameters', 'arguments'].merge(COMMON_STEP_KEYS),
|
19
|
-
'required_keys' => Set['target']
|
20
|
-
},
|
21
|
-
'task' => {
|
22
|
-
'allowed_keys' => Set['task', 'parameters'].merge(COMMON_STEP_KEYS),
|
23
|
-
'required_keys' => Set['target']
|
24
|
-
},
|
25
|
-
'plan' => {
|
26
|
-
'allowed_keys' => Set['plan', 'parameters'].merge(COMMON_STEP_KEYS),
|
27
|
-
'required_keys' => Set.new
|
28
|
-
},
|
29
|
-
'source' => {
|
30
|
-
'allowed_keys' => Set['source', 'destination'].merge(COMMON_STEP_KEYS),
|
31
|
-
'required_keys' => Set['target', 'source', 'destination']
|
32
|
-
},
|
33
|
-
'destination' => {
|
34
|
-
'allowed_keys' => Set['source', 'destination'].merge(COMMON_STEP_KEYS),
|
35
|
-
'required_keys' => Set['target', 'source', 'destination']
|
36
|
-
},
|
37
|
-
'eval' => {
|
38
|
-
'allowed_keys' => Set['eval', 'name', 'description'],
|
39
|
-
'required_keys' => Set.new
|
40
|
-
}
|
41
|
-
}.freeze
|
42
|
-
|
43
|
-
def initialize(step_body, step_number)
|
44
|
-
@body = step_body
|
45
|
-
@name = @body['name']
|
46
|
-
# For error messages
|
47
|
-
@step_number = step_number
|
48
|
-
validate_step
|
49
|
-
|
50
|
-
@type = STEP_KEYS.keys.find { |key| @body.key?(key) }
|
51
|
-
@target = @body['target']
|
11
|
+
def self.allowed_keys
|
12
|
+
Set['name', 'description', 'target']
|
52
13
|
end
|
53
14
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
result << ", #{Bolt::Util.to_code(@target)}" if @target
|
68
|
-
result << ", #{Bolt::Util.to_code(description)}" if description && type != 'plan'
|
69
|
-
result << ", #{Bolt::Util.to_code(parameters)}" unless parameters.empty?
|
70
|
-
result << ")"
|
71
|
-
when 'source'
|
72
|
-
result << "upload_file(#{Bolt::Util.to_code(body['source'])}, #{Bolt::Util.to_code(body['destination'])}"
|
73
|
-
result << ", #{Bolt::Util.to_code(@target)}" if @target
|
74
|
-
result << ", #{Bolt::Util.to_code(description)}" if description
|
75
|
-
result << ")"
|
76
|
-
when 'eval'
|
77
|
-
# We have to do a little extra parsing here, since we only need
|
78
|
-
# with() for eval blocks
|
79
|
-
code = Bolt::Util.to_code(body['eval'])
|
80
|
-
if @name && code.lines.count > 1
|
81
|
-
# A little indented niceness
|
82
|
-
indented = code.gsub(/\n/, "\n ").chomp(" ")
|
83
|
-
result << "with() || {\n #{indented}}"
|
15
|
+
COMMON_STEP_KEYS = %w[name description target].freeze
|
16
|
+
STEP_KEYS = %w[command script task plan source destination eval resources].freeze
|
17
|
+
|
18
|
+
def self.create(step_body, step_number)
|
19
|
+
type_keys = (STEP_KEYS & step_body.keys)
|
20
|
+
case type_keys.length
|
21
|
+
when 0
|
22
|
+
raise step_error("No valid action detected", step_body['name'], step_number)
|
23
|
+
when 1
|
24
|
+
type = type_keys.first
|
25
|
+
else
|
26
|
+
if type_keys.to_set == Set['source', 'destination']
|
27
|
+
type = 'upload'
|
84
28
|
else
|
85
|
-
|
29
|
+
raise step_error("Multiple action keys detected: #{type_keys.inspect}", step_body['name'], step_number)
|
86
30
|
end
|
87
|
-
else
|
88
|
-
# We should never get here
|
89
|
-
raise Bolt::YamlTranspiler::ConvertError.new("Can't convert unsupported step type #{@name}", plan_path)
|
90
31
|
end
|
91
|
-
|
92
|
-
|
32
|
+
|
33
|
+
step_class = const_get("Bolt::PAL::YamlPlan::Step::#{type.capitalize}")
|
34
|
+
step_class.validate(step_body, step_number)
|
35
|
+
step_class.new(step_body)
|
93
36
|
end
|
94
37
|
|
95
|
-
def
|
96
|
-
|
38
|
+
def initialize(step_body)
|
39
|
+
@name = step_body['name']
|
40
|
+
@description = step_body['description']
|
41
|
+
@target = step_body['target']
|
42
|
+
@body = step_body
|
43
|
+
end
|
44
|
+
|
45
|
+
def transpile
|
46
|
+
raise NotImplementedError, "Step #{@name} does not supported conversion to Puppet plan language"
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.validate(body, step_number)
|
50
|
+
validate_step_keys(body, step_number)
|
97
51
|
|
98
52
|
begin
|
99
|
-
|
53
|
+
body.each { |k, v| validate_puppet_code(k, v) }
|
100
54
|
rescue Bolt::Error => e
|
101
|
-
|
102
|
-
raise Bolt::Error.new(err, 'bolt/invalid-plan')
|
55
|
+
raise step_error(e.msg, body['name'], step_number)
|
103
56
|
end
|
104
57
|
|
105
58
|
unless body.fetch('parameters', {}).is_a?(Hash)
|
106
59
|
msg = "Parameters key must be a hash"
|
107
|
-
raise
|
60
|
+
raise step_error(msg, body['name'], step_number)
|
108
61
|
end
|
109
62
|
|
110
|
-
if
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
raise
|
63
|
+
if body.key?('name')
|
64
|
+
name = body['name']
|
65
|
+
unless name.is_a?(String) && name.match?(Bolt::PAL::YamlPlan::VAR_NAME_PATTERN)
|
66
|
+
error_message = "Invalid step name: #{name.inspect}"
|
67
|
+
raise step_error(error_message, body['name'], step_number)
|
115
68
|
end
|
116
69
|
end
|
117
70
|
end
|
118
71
|
|
119
|
-
def validate_step_keys
|
120
|
-
|
121
|
-
action = step_keys.intersection(STEP_KEYS.keys.to_set).to_a
|
122
|
-
unless action.count == 1
|
123
|
-
if action.count > 1
|
124
|
-
# Upload step is special in that it is identified by both `source` and `destination`
|
125
|
-
unless action.to_set == Set['source', 'destination']
|
126
|
-
error_message = "Multiple action keys detected: #{action.inspect}"
|
127
|
-
err = step_err_msg(error_message)
|
128
|
-
raise Bolt::Error.new(err, "bolt/invalid-plan")
|
129
|
-
end
|
130
|
-
else
|
131
|
-
error_message = "No valid action detected"
|
132
|
-
err = step_err_msg(error_message)
|
133
|
-
raise Bolt::Error.new(err, "bolt/invalid-plan")
|
134
|
-
end
|
135
|
-
end
|
72
|
+
def self.validate_step_keys(body, step_number)
|
73
|
+
step_type = name.split('::').last.downcase
|
136
74
|
|
137
75
|
# For validated step action, ensure only valid keys
|
138
|
-
|
139
|
-
|
140
|
-
error_message = "The #{
|
141
|
-
err =
|
76
|
+
illegal_keys = body.keys.to_set - allowed_keys
|
77
|
+
if illegal_keys.any?
|
78
|
+
error_message = "The #{step_type.inspect} step does not support: #{illegal_keys.to_a.inspect} key(s)"
|
79
|
+
err = step_error(error_message, body['name'], step_number)
|
142
80
|
raise Bolt::Error.new(err, "bolt/invalid-plan")
|
143
81
|
end
|
144
82
|
|
145
83
|
# Ensure all required keys are present
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
err = step_err_msg(error_message)
|
84
|
+
missing_keys = required_keys - body.keys
|
85
|
+
if missing_keys.any?
|
86
|
+
error_message = "The #{step_type.inspect} step requires: #{missing_keys.to_a.inspect} key(s)"
|
87
|
+
err = step_error(error_message, body['name'], step_number)
|
151
88
|
raise Bolt::Error.new(err, "bolt/invalid-plan")
|
152
89
|
end
|
153
90
|
end
|
154
91
|
|
155
92
|
# Recursively ensure all puppet code can be parsed
|
156
|
-
def validate_puppet_code(step_key, value)
|
93
|
+
def self.validate_puppet_code(step_key, value)
|
157
94
|
case value
|
158
95
|
when Array
|
159
96
|
value.map { |element| validate_puppet_code(step_key, element) }
|
@@ -180,16 +117,14 @@ module Bolt
|
|
180
117
|
raise Bolt::Error.new("Error parsing #{step_key.inspect}: #{e.basic_message}", "bolt/invalid-plan")
|
181
118
|
end
|
182
119
|
|
183
|
-
def
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
"Parse error in step number #{@step_number}: \n #{message}"
|
188
|
-
end
|
120
|
+
def self.step_error(message, name, step_number)
|
121
|
+
identifier = name ? name.inspect : "number #{step_number}"
|
122
|
+
error = "Parse error in step #{identifier}: \n #{message}"
|
123
|
+
Bolt::Error.new(error, 'bolt/invalid-plan')
|
189
124
|
end
|
190
125
|
|
191
126
|
# Parses the an evaluable string, optionally quote it before parsing
|
192
|
-
def parse_code_string(code, quote = false)
|
127
|
+
def self.parse_code_string(code, quote = false)
|
193
128
|
if quote
|
194
129
|
quoted = Puppet::Pops::Parser::EvaluatingParser.quote(code)
|
195
130
|
Puppet::Pops::Parser::EvaluatingParser.new.parse_string(quoted)
|
@@ -197,7 +132,20 @@ module Bolt
|
|
197
132
|
Puppet::Pops::Parser::EvaluatingParser.new.parse_string(code)
|
198
133
|
end
|
199
134
|
end
|
135
|
+
|
136
|
+
def function_call(function, args)
|
137
|
+
code_args = args.map { |arg| Bolt::Util.to_code(arg) }
|
138
|
+
"#{function}(#{code_args.join(', ')})"
|
139
|
+
end
|
200
140
|
end
|
201
141
|
end
|
202
142
|
end
|
203
143
|
end
|
144
|
+
|
145
|
+
require 'bolt/pal/yaml_plan/step/command'
|
146
|
+
require 'bolt/pal/yaml_plan/step/eval'
|
147
|
+
require 'bolt/pal/yaml_plan/step/plan'
|
148
|
+
require 'bolt/pal/yaml_plan/step/resources'
|
149
|
+
require 'bolt/pal/yaml_plan/step/script'
|
150
|
+
require 'bolt/pal/yaml_plan/step/task'
|
151
|
+
require 'bolt/pal/yaml_plan/step/upload'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class PAL
|
5
|
+
class YamlPlan
|
6
|
+
class Step
|
7
|
+
class Command < Step
|
8
|
+
def self.allowed_keys
|
9
|
+
super + Set['command']
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.required_keys
|
13
|
+
Set['target']
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(step_body)
|
17
|
+
super
|
18
|
+
@command = step_body['command']
|
19
|
+
end
|
20
|
+
|
21
|
+
def transpile
|
22
|
+
code = String.new(" ")
|
23
|
+
code << "$#{@name} = " if @name
|
24
|
+
|
25
|
+
fn = 'run_command'
|
26
|
+
args = [@command, @target]
|
27
|
+
args << @description if @description
|
28
|
+
|
29
|
+
code << function_call(fn, args)
|
30
|
+
|
31
|
+
code << "\n"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class PAL
|
5
|
+
class YamlPlan
|
6
|
+
class Step
|
7
|
+
class Eval < Step
|
8
|
+
def self.allowed_keys
|
9
|
+
super + Set['eval']
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.required_keys
|
13
|
+
Set.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(step_body)
|
17
|
+
super
|
18
|
+
@eval = step_body['eval']
|
19
|
+
end
|
20
|
+
|
21
|
+
def transpile
|
22
|
+
code = String.new(" ")
|
23
|
+
code << "$#{@name} = " if @name
|
24
|
+
|
25
|
+
code_body = Bolt::Util.to_code(@eval)
|
26
|
+
|
27
|
+
# If we're trying to assign the result of a multi-line eval to a name
|
28
|
+
# variable, we need to wrap it in `with()`.
|
29
|
+
if @name && code_body.lines.count > 1
|
30
|
+
indented = code_body.gsub(/\n/, "\n ").chomp(" ")
|
31
|
+
code << "with() || {\n #{indented}}"
|
32
|
+
else
|
33
|
+
code << code_body
|
34
|
+
end
|
35
|
+
|
36
|
+
code << "\n"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class PAL
|
5
|
+
class YamlPlan
|
6
|
+
class Step
|
7
|
+
class Plan < Step
|
8
|
+
def self.allowed_keys
|
9
|
+
super + Set['plan', 'parameters']
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.required_keys
|
13
|
+
Set.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(step_body)
|
17
|
+
super
|
18
|
+
@plan = step_body['plan']
|
19
|
+
@parameters = step_body.fetch('parameters', {})
|
20
|
+
end
|
21
|
+
|
22
|
+
def transpile
|
23
|
+
code = String.new(" ")
|
24
|
+
code << "$#{@name} = " if @name
|
25
|
+
|
26
|
+
fn = 'run_plan'
|
27
|
+
args = [@plan]
|
28
|
+
args << @parameters unless @parameters.empty?
|
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,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class PAL
|
5
|
+
class YamlPlan
|
6
|
+
class Step
|
7
|
+
class Resources < Step
|
8
|
+
def self.allowed_keys
|
9
|
+
super + Set['resources']
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.required_keys
|
13
|
+
Set['target']
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(step_body)
|
17
|
+
super
|
18
|
+
@resources = step_body['resources']
|
19
|
+
@normalized_resources = normalize_resources(@resources)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.validate(body, step_number)
|
23
|
+
super
|
24
|
+
|
25
|
+
body['resources'].each do |resource|
|
26
|
+
if resource['type'] || resource['title']
|
27
|
+
if !resource['type']
|
28
|
+
err = "Resource declaration must include type key if title key is set"
|
29
|
+
raise step_error(err, body['name'], step_number)
|
30
|
+
elsif !resource['title']
|
31
|
+
err = "Resource declaration must include title key if type key is set"
|
32
|
+
raise step_error(err, body['name'], step_number)
|
33
|
+
end
|
34
|
+
else
|
35
|
+
type_keys = (resource.keys - ['parameters'])
|
36
|
+
if type_keys.empty?
|
37
|
+
err = "Resource declaration is missing a type"
|
38
|
+
raise step_error(err, body['name'], step_number)
|
39
|
+
elsif type_keys.length > 1
|
40
|
+
err = "Resource declaration has ambiguous type: could be #{type_keys.join(' or ')}"
|
41
|
+
raise step_error(err, body['name'], step_number)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# What if this comes from a code block?
|
48
|
+
def normalize_resources(resources)
|
49
|
+
resources.map do |resource|
|
50
|
+
if resource['type'] && resource['title']
|
51
|
+
type = resource['type']
|
52
|
+
title = resource['title']
|
53
|
+
else
|
54
|
+
type, = (resource.keys - ['parameters'])
|
55
|
+
title = resource[type]
|
56
|
+
end
|
57
|
+
|
58
|
+
{ 'type' => type, 'title' => title, 'parameters' => resource['parameters'] || {} }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def body
|
63
|
+
@body.merge('resources' => @normalized_resources)
|
64
|
+
end
|
65
|
+
|
66
|
+
def transpile
|
67
|
+
code = StringIO.new
|
68
|
+
code.print " "
|
69
|
+
code.print "$#{@name} = " if @name
|
70
|
+
|
71
|
+
code.puts "apply(#{Bolt::Util.to_code(@target)}) {"
|
72
|
+
|
73
|
+
declarations = @normalized_resources.map do |resource|
|
74
|
+
type = resource['type'].is_a?(EvaluableString) ? resource['type'].value : resource['type']
|
75
|
+
title = Bolt::Util.to_code(resource['title'])
|
76
|
+
parameters = Bolt::Util.map_vals(resource['parameters']) do |val|
|
77
|
+
Bolt::Util.to_code(val)
|
78
|
+
end
|
79
|
+
|
80
|
+
resource_str = StringIO.new
|
81
|
+
if parameters.empty?
|
82
|
+
resource_str.puts " #{type} { #{title}: }"
|
83
|
+
else
|
84
|
+
resource_str.puts " #{type} { #{title}:"
|
85
|
+
parameters.each do |key, val|
|
86
|
+
resource_str.puts " #{key} => #{val},"
|
87
|
+
end
|
88
|
+
resource_str.puts " }"
|
89
|
+
end
|
90
|
+
resource_str.string
|
91
|
+
end
|
92
|
+
|
93
|
+
code.puts declarations.join(" ->\n")
|
94
|
+
|
95
|
+
code.puts " }\n"
|
96
|
+
code.string
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class PAL
|
5
|
+
class YamlPlan
|
6
|
+
class Step
|
7
|
+
class Script < Step
|
8
|
+
def self.allowed_keys
|
9
|
+
super + Set['script', 'parameters', 'arguments']
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.required_keys
|
13
|
+
Set['target']
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(step_body)
|
17
|
+
super
|
18
|
+
@script = step_body['script']
|
19
|
+
@parameters = step_body.fetch('parameters', {})
|
20
|
+
@arguments = step_body.fetch('arguments', [])
|
21
|
+
end
|
22
|
+
|
23
|
+
def transpile
|
24
|
+
code = String.new(" ")
|
25
|
+
code << "$#{@name} = " if @name
|
26
|
+
|
27
|
+
options = @parameters.dup
|
28
|
+
options['arguments'] = @arguments unless @arguments.empty?
|
29
|
+
|
30
|
+
fn = 'run_script'
|
31
|
+
args = [@script, @target]
|
32
|
+
args << @description if @description
|
33
|
+
args << options unless options.empty?
|
34
|
+
|
35
|
+
code << function_call(fn, args)
|
36
|
+
|
37
|
+
code << "\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class PAL
|
5
|
+
class YamlPlan
|
6
|
+
class Step
|
7
|
+
class Task < Step
|
8
|
+
def self.allowed_keys
|
9
|
+
super + Set['task', 'parameters']
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.required_keys
|
13
|
+
Set['target']
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(step_body)
|
17
|
+
super
|
18
|
+
@task = step_body['task']
|
19
|
+
@parameters = step_body.fetch('parameters', {})
|
20
|
+
end
|
21
|
+
|
22
|
+
def transpile
|
23
|
+
code = String.new(" ")
|
24
|
+
code << "$#{@name} = " if @name
|
25
|
+
|
26
|
+
fn = 'run_task'
|
27
|
+
args = [@task, @target]
|
28
|
+
args << @description if @description
|
29
|
+
args << @parameters unless @parameters.empty?
|
30
|
+
|
31
|
+
code << function_call(fn, args)
|
32
|
+
|
33
|
+
code << "\n"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class PAL
|
5
|
+
class YamlPlan
|
6
|
+
class Step
|
7
|
+
class Upload < Step
|
8
|
+
def self.allowed_keys
|
9
|
+
super + Set['source', 'destination']
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.required_keys
|
13
|
+
Set['target', 'source', 'destination']
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(step_body)
|
17
|
+
super
|
18
|
+
@source = step_body['source']
|
19
|
+
@destination = step_body['destination']
|
20
|
+
end
|
21
|
+
|
22
|
+
def transpile
|
23
|
+
code = String.new(" ")
|
24
|
+
code << "$#{@name} = " if @name
|
25
|
+
|
26
|
+
fn = 'upload_file'
|
27
|
+
args = [@source, @destination, @target]
|
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
|
@@ -37,8 +37,7 @@ module Bolt
|
|
37
37
|
plan_string << ") {\n"
|
38
38
|
|
39
39
|
plan_object.steps&.each do |step|
|
40
|
-
|
41
|
-
plan_string << step.transpile(@plan_path)
|
40
|
+
plan_string << step.transpile
|
42
41
|
end
|
43
42
|
|
44
43
|
plan_string << "\n return #{Bolt::Util.to_code(plan_object.return)}\n" if plan_object.return
|
data/lib/bolt/plugin.rb
CHANGED
@@ -4,15 +4,24 @@ require 'bolt/plugin/puppetdb'
|
|
4
4
|
require 'bolt/plugin/terraform'
|
5
5
|
require 'bolt/plugin/pkcs7'
|
6
6
|
require 'bolt/plugin/prompt'
|
7
|
+
require 'bolt/plugin/task'
|
7
8
|
|
8
9
|
module Bolt
|
9
10
|
class Plugin
|
11
|
+
class PluginError < Bolt::Error
|
12
|
+
def initialize(msg, plugin, hook)
|
13
|
+
mess = "Error executing plugin: #{plugin.name} from #{hook}: #{msg}"
|
14
|
+
super(mess, 'bolt/plugin-error')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
10
18
|
def self.setup(config, pdb_client)
|
11
19
|
plugins = new(config)
|
12
20
|
plugins.add_plugin(Bolt::Plugin::Puppetdb.new(pdb_client))
|
13
21
|
plugins.add_plugin(Bolt::Plugin::Terraform.new)
|
14
22
|
plugins.add_plugin(Bolt::Plugin::Prompt.new)
|
15
23
|
plugins.add_plugin(Bolt::Plugin::Pkcs7.new(config.boltdir.path, config.plugins['pkcs7'] || {}))
|
24
|
+
plugins.add_plugin(Bolt::Plugin::Task.new(config))
|
16
25
|
plugins
|
17
26
|
end
|
18
27
|
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class Plugin
|
5
|
+
class Task
|
6
|
+
def hooks
|
7
|
+
%w[inventory_targets inventory_config]
|
8
|
+
end
|
9
|
+
|
10
|
+
def name
|
11
|
+
'task'
|
12
|
+
end
|
13
|
+
|
14
|
+
# This creates it's own PAL so we don't have to pass a promise around
|
15
|
+
#
|
16
|
+
def initialize(config)
|
17
|
+
@config = config
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :config
|
21
|
+
|
22
|
+
def pal
|
23
|
+
# Hiera config should not be used yet.
|
24
|
+
@pal ||= Bolt::PAL.new(config.modulepath, config.hiera_config)
|
25
|
+
end
|
26
|
+
|
27
|
+
def executor
|
28
|
+
# Analytics should be handled at a higher level so create a new executor.
|
29
|
+
@executor ||= Bolt::Executor.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def inventory
|
33
|
+
@inventory ||= Bolt::Inventory.new({}, config)
|
34
|
+
end
|
35
|
+
|
36
|
+
def run_task(opts)
|
37
|
+
result = pal.run_task(opts['task'],
|
38
|
+
'localhost',
|
39
|
+
opts['parameters'] || {},
|
40
|
+
executor,
|
41
|
+
inventory).first
|
42
|
+
|
43
|
+
raise Bolt::Error.new(result.error_hash['msg'], result.error_hash['kind']) if result.error_hash
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
def validate_options(opts)
|
48
|
+
raise Bolt::ValidationError, "Task plugin requires that the 'task' is specified" unless opts['task']
|
49
|
+
|
50
|
+
task = pal.task_signature(opts['task'])
|
51
|
+
|
52
|
+
raise Bolt::ValidationError, "Could not find task #{opts['task']}" unless task
|
53
|
+
|
54
|
+
errors = []
|
55
|
+
unless task.runnable_with?(opts['parameters'] || {}) { |msg| errors << msg }
|
56
|
+
# This relies on runnable with printing a partial message before the first real error
|
57
|
+
raise Bolt::ValidationError, "Invalid parameters for #{errors.join("\n")}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
alias validate_inventory_config validate_options
|
61
|
+
|
62
|
+
def inventory_config(opts)
|
63
|
+
result = run_task(opts)
|
64
|
+
|
65
|
+
unless result.value.include?('config')
|
66
|
+
raise Bolt::ValidationError, "Task result did not return 'config': #{result.value}"
|
67
|
+
end
|
68
|
+
|
69
|
+
result['config']
|
70
|
+
end
|
71
|
+
|
72
|
+
def inventory_targets(opts)
|
73
|
+
raise Bolt::ValidationError, "Task plugin requires that the 'task' is specified" unless opts['task']
|
74
|
+
|
75
|
+
result = run_task(opts)
|
76
|
+
|
77
|
+
targets = result['targets']
|
78
|
+
unless targets.is_a?(Array)
|
79
|
+
raise Bolt::ValidationError, "Task result did not return a targets array: #{result.value}"
|
80
|
+
end
|
81
|
+
|
82
|
+
unless targets.all? { |t| t.is_a?(Hash) }
|
83
|
+
msg = "All targets returned by an inventory targets task must be hashes, got: #{targets}"
|
84
|
+
raise Bolt::ValidationError, msg
|
85
|
+
end
|
86
|
+
|
87
|
+
targets
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/bolt/transport/orch.rb
CHANGED
@@ -19,7 +19,7 @@ module Bolt
|
|
19
19
|
def initialize(opts, plan_context, logger)
|
20
20
|
@logger = logger
|
21
21
|
@key = self.class.get_key(opts)
|
22
|
-
client_keys = %w[service-url token-file cacert]
|
22
|
+
client_keys = %w[service-url token-file cacert job-poll-interval job-poll-timeout]
|
23
23
|
client_opts = client_keys.each_with_object({}) do |k, acc|
|
24
24
|
acc[k] = opts[k] if opts.include?(k)
|
25
25
|
end
|
data/lib/bolt/version.rb
CHANGED
@@ -62,11 +62,7 @@ module BoltServer
|
|
62
62
|
|
63
63
|
task = Bolt::Task::PuppetServer.new(body['task'], @file_cache)
|
64
64
|
parameters = body['parameters'] || {}
|
65
|
-
|
66
|
-
|
67
|
-
# Since this will only be on one node we can just return the first result
|
68
|
-
result = scrub_stack_trace(results.first.status_hash)
|
69
|
-
[200, result.to_json]
|
65
|
+
@executor.run_task(target, task, parameters)
|
70
66
|
end
|
71
67
|
|
72
68
|
get '/' do
|
@@ -105,10 +101,13 @@ module BoltServer
|
|
105
101
|
opts.delete('private-key-content')
|
106
102
|
end
|
107
103
|
opts['load-config'] = false
|
108
|
-
|
109
104
|
target = [Bolt::Target.new(body['target']['hostname'], opts)]
|
110
105
|
|
111
|
-
method(params[:action]).call(target, body)
|
106
|
+
results = method(params[:action]).call(target, body)
|
107
|
+
|
108
|
+
# Since this will only be on one node we can just return the first result
|
109
|
+
result = scrub_stack_trace(results.first.status_hash)
|
110
|
+
[200, result.to_json]
|
112
111
|
end
|
113
112
|
|
114
113
|
post '/winrm/:action' do
|
@@ -121,10 +120,13 @@ module BoltServer
|
|
121
120
|
return [400, error.to_json] unless error.nil?
|
122
121
|
|
123
122
|
opts = body['target'].clone.merge('protocol' => 'winrm')
|
124
|
-
|
125
123
|
target = [Bolt::Target.new(body['target']['hostname'], opts)]
|
126
124
|
|
127
|
-
method(params[:action]).call(target, body)
|
125
|
+
results = method(params[:action]).call(target, body)
|
126
|
+
|
127
|
+
# Since this will only be on one node we can just return the first result
|
128
|
+
result = scrub_stack_trace(results.first.status_hash)
|
129
|
+
[200, result.to_json]
|
128
130
|
end
|
129
131
|
|
130
132
|
error 404 do
|
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.26.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-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -386,12 +386,20 @@ files:
|
|
386
386
|
- lib/bolt/pal/yaml_plan/loader.rb
|
387
387
|
- lib/bolt/pal/yaml_plan/parameter.rb
|
388
388
|
- lib/bolt/pal/yaml_plan/step.rb
|
389
|
+
- lib/bolt/pal/yaml_plan/step/command.rb
|
390
|
+
- lib/bolt/pal/yaml_plan/step/eval.rb
|
391
|
+
- lib/bolt/pal/yaml_plan/step/plan.rb
|
392
|
+
- lib/bolt/pal/yaml_plan/step/resources.rb
|
393
|
+
- lib/bolt/pal/yaml_plan/step/script.rb
|
394
|
+
- lib/bolt/pal/yaml_plan/step/task.rb
|
395
|
+
- lib/bolt/pal/yaml_plan/step/upload.rb
|
389
396
|
- lib/bolt/pal/yaml_plan/transpiler.rb
|
390
397
|
- lib/bolt/plan_result.rb
|
391
398
|
- lib/bolt/plugin.rb
|
392
399
|
- lib/bolt/plugin/pkcs7.rb
|
393
400
|
- lib/bolt/plugin/prompt.rb
|
394
401
|
- lib/bolt/plugin/puppetdb.rb
|
402
|
+
- lib/bolt/plugin/task.rb
|
395
403
|
- lib/bolt/plugin/terraform.rb
|
396
404
|
- lib/bolt/puppetdb.rb
|
397
405
|
- lib/bolt/puppetdb/client.rb
|