bolt 2.44.0 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Puppetfile +11 -9
- data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +25 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +20 -2
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +2 -2
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +44 -5
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +7 -3
- data/bolt-modules/file/lib/puppet/functions/file/read.rb +3 -2
- data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +20 -2
- data/bolt-modules/prompt/lib/puppet/functions/prompt/menu.rb +103 -0
- data/lib/bolt/apply_result.rb +1 -1
- data/lib/bolt/bolt_option_parser.rb +9 -123
- data/lib/bolt/cli.rb +125 -127
- data/lib/bolt/config.rb +39 -214
- data/lib/bolt/config/options.rb +34 -125
- data/lib/bolt/config/transport/local.rb +1 -0
- data/lib/bolt/config/transport/lxd.rb +23 -0
- data/lib/bolt/config/transport/options.rb +9 -2
- data/lib/bolt/executor.rb +20 -5
- data/lib/bolt/logger.rb +9 -1
- data/lib/bolt/module_installer.rb +2 -2
- data/lib/bolt/module_installer/puppetfile.rb +2 -2
- data/lib/bolt/module_installer/specs/forge_spec.rb +2 -2
- data/lib/bolt/module_installer/specs/git_spec.rb +2 -2
- data/lib/bolt/node/output.rb +14 -4
- data/lib/bolt/outputter/human.rb +52 -24
- data/lib/bolt/outputter/json.rb +16 -16
- data/lib/bolt/pal.rb +26 -5
- data/lib/bolt/pal/yaml_plan.rb +1 -2
- data/lib/bolt/pal/yaml_plan/evaluator.rb +5 -153
- data/lib/bolt/pal/yaml_plan/step.rb +91 -52
- data/lib/bolt/pal/yaml_plan/step/command.rb +21 -13
- data/lib/bolt/pal/yaml_plan/step/download.rb +15 -16
- data/lib/bolt/pal/yaml_plan/step/eval.rb +11 -11
- data/lib/bolt/pal/yaml_plan/step/message.rb +13 -4
- data/lib/bolt/pal/yaml_plan/step/plan.rb +19 -15
- data/lib/bolt/pal/yaml_plan/step/resources.rb +82 -21
- data/lib/bolt/pal/yaml_plan/step/script.rb +36 -17
- data/lib/bolt/pal/yaml_plan/step/task.rb +19 -16
- data/lib/bolt/pal/yaml_plan/step/upload.rb +16 -17
- data/lib/bolt/pal/yaml_plan/transpiler.rb +3 -3
- data/lib/bolt/plan_creator.rb +1 -1
- data/lib/bolt/plugin/module.rb +0 -23
- data/lib/bolt/plugin/puppet_connect_data.rb +45 -3
- data/lib/bolt/project.rb +16 -56
- data/lib/bolt/project_manager.rb +5 -4
- data/lib/bolt/project_manager/module_migrator.rb +7 -6
- data/lib/bolt/result.rb +10 -11
- data/lib/bolt/shell.rb +16 -0
- data/lib/bolt/shell/bash.rb +61 -31
- data/lib/bolt/shell/bash/tmpdir.rb +2 -2
- data/lib/bolt/shell/powershell.rb +35 -14
- data/lib/bolt/shell/powershell/snippets.rb +37 -150
- data/lib/bolt/task.rb +1 -1
- data/lib/bolt/transport/base.rb +0 -9
- data/lib/bolt/transport/docker.rb +1 -125
- data/lib/bolt/transport/docker/connection.rb +86 -161
- data/lib/bolt/transport/local.rb +1 -9
- data/lib/bolt/transport/lxd.rb +26 -0
- data/lib/bolt/transport/lxd/connection.rb +99 -0
- data/lib/bolt/transport/orch.rb +13 -5
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/transport/winrm/connection.rb +1 -1
- data/lib/bolt/util.rb +8 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/transport_app.rb +61 -33
- data/lib/bolt_spec/bolt_context.rb +9 -4
- data/lib/bolt_spec/plans.rb +1 -109
- data/lib/bolt_spec/plans/action_stubs.rb +1 -1
- data/lib/bolt_spec/plans/action_stubs/command_stub.rb +8 -1
- data/lib/bolt_spec/plans/action_stubs/script_stub.rb +8 -1
- data/lib/bolt_spec/plans/mock_executor.rb +4 -0
- data/modules/aggregate/plans/count.pp +21 -0
- data/modules/aggregate/plans/targets.pp +21 -0
- data/modules/puppet_connect/plans/test_input_data.pp +67 -0
- data/modules/puppetdb_fact/plans/init.pp +10 -0
- metadata +7 -3
- data/modules/aggregate/plans/nodes.pp +0 -36
data/lib/bolt/pal.rb
CHANGED
@@ -215,6 +215,7 @@ module Bolt
|
|
215
215
|
def with_bolt_executor(executor, inventory, pdb_client = nil, applicator = nil, &block)
|
216
216
|
setup
|
217
217
|
opts = {
|
218
|
+
bolt_project: @project,
|
218
219
|
bolt_executor: executor,
|
219
220
|
bolt_inventory: inventory,
|
220
221
|
bolt_pdb_client: pdb_client,
|
@@ -384,7 +385,7 @@ module Bolt
|
|
384
385
|
plan_cache[plan_name] = info
|
385
386
|
end
|
386
387
|
|
387
|
-
list << [plan_name] unless info['private']
|
388
|
+
list << [plan_name, info['description']] unless info['private']
|
388
389
|
end
|
389
390
|
|
390
391
|
File.write(@project.plan_cache_file, plan_cache.to_json) if updated
|
@@ -445,11 +446,11 @@ module Bolt
|
|
445
446
|
params[name] = { 'type' => param.types.first }
|
446
447
|
params[name]['sensitive'] = param.types.first =~ /\ASensitive(\[.*\])?\z/ ? true : false
|
447
448
|
params[name]['default_value'] = defaults[name] if defaults.key?(name)
|
448
|
-
params[name]['description'] = param.text
|
449
|
+
params[name]['description'] = param.text if param.text && !param.text.empty?
|
449
450
|
else
|
450
451
|
Bolt::Logger.warn(
|
451
452
|
"missing_plan_parameter",
|
452
|
-
"The documented parameter '#{name}' does not exist in plan
|
453
|
+
"The documented parameter '#{name}' does not exist in signature for plan '#{plan.name}'"
|
453
454
|
)
|
454
455
|
end
|
455
456
|
end
|
@@ -520,10 +521,30 @@ module Bolt
|
|
520
521
|
end
|
521
522
|
end
|
522
523
|
|
523
|
-
def convert_plan(
|
524
|
+
def convert_plan(plan)
|
525
|
+
path = File.expand_path(plan)
|
526
|
+
|
527
|
+
# If the path doesn't exist, check if it's a plan name
|
528
|
+
unless File.exist?(path)
|
529
|
+
in_bolt_compiler do |compiler|
|
530
|
+
sig = compiler.plan_signature(plan)
|
531
|
+
|
532
|
+
# If the plan was loaded, look for it on the module loader
|
533
|
+
# There has to be an easier way to do this...
|
534
|
+
if sig
|
535
|
+
type = compiler.list_plans.find { |p| p.name == plan }
|
536
|
+
path = sig.instance_variable_get(:@plan_func)
|
537
|
+
.loader
|
538
|
+
.find(type)
|
539
|
+
.origin
|
540
|
+
.first
|
541
|
+
end
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
524
545
|
Puppet[:tasks] = true
|
525
546
|
transpiler = YamlPlan::Transpiler.new
|
526
|
-
transpiler.transpile(
|
547
|
+
transpiler.transpile(path)
|
527
548
|
end
|
528
549
|
|
529
550
|
# Returns a mapping of all modules available to the Bolt compiler
|
data/lib/bolt/pal/yaml_plan.rb
CHANGED
@@ -73,8 +73,7 @@ module Bolt
|
|
73
73
|
def duplicate_check(used_names, name, step_number)
|
74
74
|
if used_names.include?(name)
|
75
75
|
error_message = "Duplicate step name or parameter detected: #{name.inspect}"
|
76
|
-
|
77
|
-
raise Bolt::Error.new(err, "bolt/invalid-plan")
|
76
|
+
raise Step::StepError.new(error_message, name, step_number)
|
78
77
|
end
|
79
78
|
end
|
80
79
|
|
@@ -12,165 +12,15 @@ module Bolt
|
|
12
12
|
@evaluator = Puppet::Pops::Parser::EvaluatingParser.new
|
13
13
|
end
|
14
14
|
|
15
|
-
def dispatch_step(scope, step)
|
16
|
-
step_body = evaluate_code_blocks(scope, step.body)
|
17
|
-
|
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)
|
23
|
-
end
|
24
|
-
|
25
|
-
def task_step(scope, step)
|
26
|
-
task = step['task']
|
27
|
-
targets = step['targets'] || step['target']
|
28
|
-
description = step['description']
|
29
|
-
params = step['parameters'] || {}
|
30
|
-
|
31
|
-
args = if description
|
32
|
-
[task, targets, description, params]
|
33
|
-
else
|
34
|
-
[task, targets, params]
|
35
|
-
end
|
36
|
-
|
37
|
-
scope.call_function('run_task', args)
|
38
|
-
end
|
39
|
-
|
40
|
-
def plan_step(scope, step)
|
41
|
-
plan = step['plan']
|
42
|
-
parameters = step['parameters'] || {}
|
43
|
-
|
44
|
-
args = [plan, parameters]
|
45
|
-
|
46
|
-
scope.call_function('run_plan', args)
|
47
|
-
end
|
48
|
-
|
49
|
-
def script_step(scope, step)
|
50
|
-
script = step['script']
|
51
|
-
targets = step['targets'] || step['target']
|
52
|
-
description = step['description']
|
53
|
-
arguments = step['arguments'] || []
|
54
|
-
|
55
|
-
options = { 'arguments' => arguments }
|
56
|
-
args = if description
|
57
|
-
[script, targets, description, options]
|
58
|
-
else
|
59
|
-
[script, targets, options]
|
60
|
-
end
|
61
|
-
|
62
|
-
scope.call_function('run_script', args)
|
63
|
-
end
|
64
|
-
|
65
|
-
def command_step(scope, step)
|
66
|
-
command = step['command']
|
67
|
-
targets = step['targets'] || step['target']
|
68
|
-
description = step['description']
|
69
|
-
|
70
|
-
args = [command, targets]
|
71
|
-
args << description if description
|
72
|
-
scope.call_function('run_command', args)
|
73
|
-
end
|
74
|
-
|
75
|
-
def upload_step(scope, step)
|
76
|
-
source = step['upload'] || step['source']
|
77
|
-
destination = step['destination']
|
78
|
-
targets = step['targets'] || step['target']
|
79
|
-
description = step['description']
|
80
|
-
|
81
|
-
args = [source, destination, targets]
|
82
|
-
args << description if description
|
83
|
-
scope.call_function('upload_file', args)
|
84
|
-
end
|
85
|
-
|
86
|
-
def download_step(scope, step)
|
87
|
-
source = step['download']
|
88
|
-
destination = step['destination']
|
89
|
-
targets = step['targets'] || step['target']
|
90
|
-
description = step['description']
|
91
|
-
|
92
|
-
args = [source, destination, targets]
|
93
|
-
args << description if description
|
94
|
-
scope.call_function('download_file', args)
|
95
|
-
end
|
96
|
-
|
97
|
-
def eval_step(_scope, step)
|
98
|
-
step['eval']
|
99
|
-
end
|
100
|
-
|
101
|
-
def resources_step(scope, step)
|
102
|
-
targets = step['targets'] || step['target']
|
103
|
-
|
104
|
-
# TODO: Only call apply_prep when needed
|
105
|
-
scope.call_function('apply_prep', targets)
|
106
|
-
manifest = generate_manifest(step['resources'])
|
107
|
-
|
108
|
-
apply_manifest(scope, targets, manifest)
|
109
|
-
end
|
110
|
-
|
111
|
-
def message_step(scope, step)
|
112
|
-
scope.call_function('out::message', [step['message']])
|
113
|
-
end
|
114
|
-
|
115
|
-
def generate_manifest(resources)
|
116
|
-
# inspect returns the Ruby representation of the resource hashes,
|
117
|
-
# which happens to be the same as the Puppet representation
|
118
|
-
puppet_resources = resources.inspect
|
119
|
-
|
120
|
-
# Because the :tasks setting globally controls which mode the parser
|
121
|
-
# is in, we need to make this snippet of non-tasks manifest code
|
122
|
-
# parseable in tasks mode. The way to do that is by putting it in an
|
123
|
-
# apply statement and taking the body.
|
124
|
-
<<~MANIFEST
|
125
|
-
apply('placeholder') {
|
126
|
-
$resources = #{puppet_resources}
|
127
|
-
$resources.each |$res| {
|
128
|
-
Resource[$res['type']] { $res['title']:
|
129
|
-
* => $res['parameters'],
|
130
|
-
}
|
131
|
-
}
|
132
|
-
|
133
|
-
# Add relationships if there is more than one resource
|
134
|
-
if $resources.length > 1 {
|
135
|
-
($resources.length - 1).each |$index| {
|
136
|
-
$lhs = $resources[$index]
|
137
|
-
$rhs = $resources[$index+1]
|
138
|
-
$lhs_resource = Resource[$lhs['type'] , $lhs['title']]
|
139
|
-
$rhs_resource = Resource[$rhs['type'] , $rhs['title']]
|
140
|
-
$lhs_resource -> $rhs_resource
|
141
|
-
}
|
142
|
-
}
|
143
|
-
}
|
144
|
-
MANIFEST
|
145
|
-
end
|
146
|
-
|
147
|
-
def apply_manifest(scope, targets, manifest)
|
148
|
-
ast = @evaluator.parse_string(manifest)
|
149
|
-
apply_block = ast.body.body
|
150
|
-
applicator = Puppet.lookup(:apply_executor)
|
151
|
-
applicator.apply([targets], apply_block, scope)
|
152
|
-
end
|
153
|
-
|
154
15
|
# This is the method that Puppet calls to evaluate the plan. The name
|
155
16
|
# makes more sense for .pp plans.
|
17
|
+
#
|
156
18
|
def evaluate_block_with_bindings(closure_scope, args_hash, plan)
|
157
|
-
if plan.steps.any? { |step| step.body.key?('target') }
|
158
|
-
msg = "The 'target' parameter for YAML plan steps is deprecated and will be removed "\
|
159
|
-
"in a future version of Bolt. Use the 'targets' parameter instead."
|
160
|
-
Bolt::Logger.deprecate("yaml_plan_target", msg)
|
161
|
-
end
|
162
|
-
|
163
|
-
if plan.steps.any? { |step| step.body.key?('source') }
|
164
|
-
msg = "The 'source' parameter for YAML plan upload steps is deprecated and will be removed "\
|
165
|
-
"in a future version of Bolt. Use the 'upload' parameter instead."
|
166
|
-
Bolt::Logger.deprecate("yaml_plan_source", msg)
|
167
|
-
end
|
168
|
-
|
169
19
|
plan_result = closure_scope.with_local_scope(args_hash) do |scope|
|
170
20
|
plan.steps.each do |step|
|
171
|
-
step_result =
|
21
|
+
step_result = step.evaluate(scope, self)
|
172
22
|
|
173
|
-
scope.setvar(step.name, step_result) if step.name
|
23
|
+
scope.setvar(step.body['name'], step_result) if step.body['name']
|
174
24
|
end
|
175
25
|
|
176
26
|
evaluate_code_blocks(scope, plan.return)
|
@@ -180,6 +30,7 @@ module Bolt
|
|
180
30
|
end
|
181
31
|
|
182
32
|
# Recursively evaluate any EvaluableString instances in the object.
|
33
|
+
#
|
183
34
|
def evaluate_code_blocks(scope, value)
|
184
35
|
# XXX We should establish a local scope here probably
|
185
36
|
case value
|
@@ -204,6 +55,7 @@ module Bolt
|
|
204
55
|
# Occasionally the Closure will ask us to evaluate what it assumes are
|
205
56
|
# AST objects. Because we've sidestepped the AST, they aren't, so just
|
206
57
|
# return the values as already evaluated.
|
58
|
+
#
|
207
59
|
def evaluate(value, _scope)
|
208
60
|
value
|
209
61
|
end
|
@@ -6,41 +6,56 @@ module Bolt
|
|
6
6
|
class PAL
|
7
7
|
class YamlPlan
|
8
8
|
class Step
|
9
|
-
attr_reader :
|
10
|
-
|
11
|
-
def self.allowed_keys
|
12
|
-
Set['name', 'description', 'target', 'targets']
|
13
|
-
end
|
9
|
+
attr_reader :body
|
14
10
|
|
15
11
|
STEP_KEYS = %w[
|
16
12
|
command
|
17
|
-
destination
|
18
13
|
download
|
19
14
|
eval
|
20
15
|
message
|
21
16
|
plan
|
22
17
|
resources
|
23
18
|
script
|
24
|
-
source
|
25
19
|
task
|
26
20
|
upload
|
27
21
|
].freeze
|
28
22
|
|
23
|
+
class StepError < Bolt::Error
|
24
|
+
def initialize(message, name, step_number)
|
25
|
+
identifier = name ? name.inspect : "number #{step_number}"
|
26
|
+
error = "Parse error in step #{identifier}: \n #{message}"
|
27
|
+
|
28
|
+
super(error, 'bolt/invalid-plan')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Keys that are allowed for the step
|
33
|
+
#
|
34
|
+
def self.allowed_keys
|
35
|
+
required_keys + option_keys + Set['name', 'description', 'targets']
|
36
|
+
end
|
37
|
+
|
38
|
+
# Keys that translate to metaparameters for the plan step's function call
|
39
|
+
#
|
40
|
+
def self.option_keys
|
41
|
+
Set.new
|
42
|
+
end
|
43
|
+
|
44
|
+
# Keys that are required for the step
|
45
|
+
#
|
46
|
+
def self.required_keys
|
47
|
+
Set.new
|
48
|
+
end
|
49
|
+
|
29
50
|
def self.create(step_body, step_number)
|
30
51
|
type_keys = (STEP_KEYS & step_body.keys)
|
31
52
|
case type_keys.length
|
32
53
|
when 0
|
33
|
-
raise
|
54
|
+
raise StepError.new("No valid action detected", step_body['name'], step_number)
|
34
55
|
when 1
|
35
56
|
type = type_keys.first
|
36
57
|
else
|
37
|
-
|
38
|
-
type = 'upload'
|
39
|
-
elsif type_keys.to_set == Set['download', 'destination']
|
40
|
-
type = 'download'
|
41
|
-
else
|
42
|
-
raise step_error("Multiple action keys detected: #{type_keys.inspect}", step_body['name'], step_number)
|
43
|
-
end
|
58
|
+
raise StepError.new("Multiple action keys detected: #{type_keys.inspect}", step_body['name'], step_number)
|
44
59
|
end
|
45
60
|
|
46
61
|
step_class = const_get("Bolt::PAL::YamlPlan::Step::#{type.capitalize}")
|
@@ -48,15 +63,49 @@ module Bolt
|
|
48
63
|
step_class.new(step_body)
|
49
64
|
end
|
50
65
|
|
51
|
-
def initialize(
|
52
|
-
@
|
53
|
-
@description = step_body['description']
|
54
|
-
@targets = step_body['targets'] || step_body['target']
|
55
|
-
@body = step_body
|
66
|
+
def initialize(body)
|
67
|
+
@body = body
|
56
68
|
end
|
57
69
|
|
70
|
+
# Transpiles the step into the plan language
|
71
|
+
#
|
58
72
|
def transpile
|
59
|
-
|
73
|
+
code = String.new(" ")
|
74
|
+
code << "$#{body['name']} = " if body['name']
|
75
|
+
code << function_call(function, format_args(body))
|
76
|
+
code << "\n"
|
77
|
+
end
|
78
|
+
|
79
|
+
# Evaluates the step
|
80
|
+
#
|
81
|
+
def evaluate(scope, evaluator)
|
82
|
+
evaluated = evaluator.evaluate_code_blocks(scope, body)
|
83
|
+
scope.call_function(function, format_args(evaluated))
|
84
|
+
end
|
85
|
+
|
86
|
+
# Formats a list of args from the provided body
|
87
|
+
#
|
88
|
+
private def format_args(_body)
|
89
|
+
raise NotImplementedError, "Step class #{self.class} does not implement #format_args"
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns the step's corresponding Puppet language function call
|
93
|
+
#
|
94
|
+
private def function_call(function, args)
|
95
|
+
code_args = args.map { |arg| Bolt::Util.to_code(arg) }
|
96
|
+
"#{function}(#{code_args.join(', ')})"
|
97
|
+
end
|
98
|
+
|
99
|
+
# The function that corresponds to the step
|
100
|
+
#
|
101
|
+
private def function
|
102
|
+
raise NotImplementedError, "Step class #{self.class} does not implement #function"
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns a hash of options formatted for function calls
|
106
|
+
#
|
107
|
+
private def format_options(body)
|
108
|
+
body.slice(*self.class.option_keys).transform_keys { |key| "_#{key}" }
|
60
109
|
end
|
61
110
|
|
62
111
|
def self.validate(body, step_number)
|
@@ -65,19 +114,35 @@ module Bolt
|
|
65
114
|
begin
|
66
115
|
body.each { |k, v| validate_puppet_code(k, v) }
|
67
116
|
rescue Bolt::Error => e
|
68
|
-
raise
|
117
|
+
raise StepError.new(e.msg, body['name'], step_number)
|
118
|
+
end
|
119
|
+
|
120
|
+
if body.key?('parameters')
|
121
|
+
unless body['parameters'].is_a?(Hash)
|
122
|
+
raise StepError.new("Parameters key must be a hash", body['name'], step_number)
|
123
|
+
end
|
124
|
+
|
125
|
+
metaparams = option_keys.map { |key| "_#{key}" }
|
126
|
+
|
127
|
+
if (dups = body['parameters'].keys & metaparams).any?
|
128
|
+
raise StepError.new(
|
129
|
+
"Cannot specify metaparameters when using top-level keys with same name: #{dups.join(', ')}",
|
130
|
+
body['name'],
|
131
|
+
step_number
|
132
|
+
)
|
133
|
+
end
|
69
134
|
end
|
70
135
|
|
71
136
|
unless body.fetch('parameters', {}).is_a?(Hash)
|
72
137
|
msg = "Parameters key must be a hash"
|
73
|
-
raise
|
138
|
+
raise StepError.new(msg, body['name'], step_number)
|
74
139
|
end
|
75
140
|
|
76
141
|
if body.key?('name')
|
77
142
|
name = body['name']
|
78
143
|
unless name.is_a?(String) && name.match?(Bolt::PAL::YamlPlan::VAR_NAME_PATTERN)
|
79
144
|
error_message = "Invalid step name: #{name.inspect}"
|
80
|
-
raise
|
145
|
+
raise StepError.new(error_message, body['name'], step_number)
|
81
146
|
end
|
82
147
|
end
|
83
148
|
end
|
@@ -89,30 +154,15 @@ module Bolt
|
|
89
154
|
illegal_keys = body.keys.to_set - allowed_keys
|
90
155
|
if illegal_keys.any?
|
91
156
|
error_message = "The #{step_type.inspect} step does not support: #{illegal_keys.to_a.inspect} key(s)"
|
92
|
-
|
93
|
-
raise Bolt::Error.new(err, "bolt/invalid-plan")
|
157
|
+
raise StepError.new(error_message, body['name'], step_number)
|
94
158
|
end
|
95
159
|
|
96
160
|
# Ensure all required keys are present
|
97
161
|
missing_keys = required_keys - body.keys
|
98
162
|
|
99
|
-
# Handle cases where steps with a required 'targets' key are using the deprecated
|
100
|
-
# 'target' key instead.
|
101
|
-
# TODO: Remove this when 'target' is removed
|
102
|
-
if body.include?('target')
|
103
|
-
missing_keys -= ['targets']
|
104
|
-
end
|
105
|
-
|
106
|
-
# Handle cases where upload step uses deprecated 'source' key instead of 'upload'
|
107
|
-
# TODO: Remove when 'source' is removed
|
108
|
-
if body.include?('source')
|
109
|
-
missing_keys -= ['upload']
|
110
|
-
end
|
111
|
-
|
112
163
|
if missing_keys.any?
|
113
164
|
error_message = "The #{step_type.inspect} step requires: #{missing_keys.to_a.inspect} key(s)"
|
114
|
-
|
115
|
-
raise Bolt::Error.new(err, "bolt/invalid-plan")
|
165
|
+
raise StepError.new(error_message, body['name'], step_number)
|
116
166
|
end
|
117
167
|
end
|
118
168
|
|
@@ -144,12 +194,6 @@ module Bolt
|
|
144
194
|
raise Bolt::Error.new("Error parsing #{step_key.inspect}: #{e.basic_message}", "bolt/invalid-plan")
|
145
195
|
end
|
146
196
|
|
147
|
-
def self.step_error(message, name, step_number)
|
148
|
-
identifier = name ? name.inspect : "number #{step_number}"
|
149
|
-
error = "Parse error in step #{identifier}: \n #{message}"
|
150
|
-
Bolt::Error.new(error, 'bolt/invalid-plan')
|
151
|
-
end
|
152
|
-
|
153
197
|
# Parses the an evaluable string, optionally quote it before parsing
|
154
198
|
def self.parse_code_string(code, quote = false)
|
155
199
|
if quote
|
@@ -159,11 +203,6 @@ module Bolt
|
|
159
203
|
Puppet::Pops::Parser::EvaluatingParser.new.parse_string(code)
|
160
204
|
end
|
161
205
|
end
|
162
|
-
|
163
|
-
def function_call(function, args)
|
164
|
-
code_args = args.map { |arg| Bolt::Util.to_code(arg) }
|
165
|
-
"#{function}(#{code_args.join(', ')})"
|
166
|
-
end
|
167
206
|
end
|
168
207
|
end
|
169
208
|
end
|