bolt 1.39.0 → 1.40.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/catch_errors.rb +2 -2
- data/lib/bolt/inventory.rb +1 -1
- data/lib/bolt/outputter/human.rb +5 -2
- data/lib/bolt/pal.rb +67 -27
- data/lib/bolt/pal/yaml_plan.rb +3 -2
- data/lib/bolt/pal/yaml_plan/loader.rb +5 -2
- data/lib/bolt/pal/yaml_plan/parameter.rb +2 -1
- data/lib/bolt/pal/yaml_plan/transpiler.rb +1 -13
- data/lib/bolt/plugin.rb +1 -1
- data/lib/bolt/plugin/puppetdb.rb +16 -4
- data/lib/bolt/util.rb +2 -2
- data/lib/bolt/version.rb +1 -1
- data/modules/canary/plans/init.pp +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f796af64ec2860ec9e3fc3809e246bca8ebafa4199c50757c3c63749069c4017
|
4
|
+
data.tar.gz: 7a11411a59cd4c5eb50c9ddc9ed02c5b0838aa6cab860f15ef46d76be7f4a34f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1365e9a864d04685b3e922d810fbdad173e8f703b28c004c1005032b9666f56bcc3b251c25292e8d3239417a5a9a1b3c53ed49619e23d8f89fed341b6bde2c0
|
7
|
+
data.tar.gz: 2c1700287f8a9879b510d8d2cf91b9f044e44546ef5ec2f72b8e5a6a4ad1871e0f21737b67743971cdb1f8c5df9d9321352726aadaaad5367cd2f7702b89e1f1
|
@@ -44,9 +44,9 @@ Puppet::Functions.create_function(:catch_errors) do
|
|
44
44
|
rescue Puppet::PreformattedError => e
|
45
45
|
if e.cause.is_a?(Bolt::Error)
|
46
46
|
if error_types.nil?
|
47
|
-
|
47
|
+
e.cause.to_puppet_error
|
48
48
|
elsif error_types.include?(e.cause.to_h['kind'])
|
49
|
-
|
49
|
+
e.cause.to_puppet_error
|
50
50
|
else
|
51
51
|
raise e
|
52
52
|
end
|
data/lib/bolt/inventory.rb
CHANGED
@@ -212,7 +212,7 @@ module Bolt
|
|
212
212
|
}
|
213
213
|
data = Bolt::Util.deep_merge(defaults, data)
|
214
214
|
# If features is an empty array deep_merge won't add the puppet-agent
|
215
|
-
data['features']
|
215
|
+
data['features'] += ['puppet-agent'] if data['features'].empty?
|
216
216
|
data
|
217
217
|
end
|
218
218
|
|
data/lib/bolt/outputter/human.rb
CHANGED
@@ -257,15 +257,18 @@ module Bolt
|
|
257
257
|
plan_info = +""
|
258
258
|
usage = +"bolt plan run #{plan['name']}"
|
259
259
|
|
260
|
-
plan['parameters']
|
260
|
+
plan['parameters'].each do |name, p|
|
261
261
|
pretty_params << "- #{name}: #{p['type']}\n"
|
262
|
+
pretty_params << " Default: #{p['default_value']}\n" unless p['default_value'].nil?
|
263
|
+
pretty_params << " #{p['description']}\n" if p['description']
|
262
264
|
usage << (p.include?('default_value') ? " [#{name}=<value>]" : " #{name}=<value>")
|
263
265
|
end
|
264
266
|
|
265
267
|
plan_info << "\n#{plan['name']}"
|
268
|
+
plan_info << " - #{plan['description']}" if plan['description']
|
266
269
|
plan_info << "\n\n"
|
267
270
|
plan_info << "USAGE:\n#{usage}\n\n"
|
268
|
-
plan_info << "PARAMETERS:\n#{pretty_params}\n"
|
271
|
+
plan_info << "PARAMETERS:\n#{pretty_params}\n" unless plan['parameters'].empty?
|
269
272
|
plan_info << "MODULE:\n"
|
270
273
|
|
271
274
|
path = plan['module']
|
data/lib/bolt/pal.rb
CHANGED
@@ -299,38 +299,78 @@ module Bolt
|
|
299
299
|
end
|
300
300
|
end
|
301
301
|
|
302
|
-
# This converts a plan signature object into a format used by the outputter.
|
303
|
-
# Must be called from within bolt compiler to pickup type aliases used in the plan signature.
|
304
|
-
def plan_hash(plan_name, plan)
|
305
|
-
elements = plan.params_type.elements || []
|
306
|
-
parameters = elements.each_with_object({}) do |param, acc|
|
307
|
-
type = if param.value_type.is_a?(Puppet::Pops::Types::PTypeAliasType)
|
308
|
-
param.value_type.name
|
309
|
-
else
|
310
|
-
param.value_type.to_s
|
311
|
-
end
|
312
|
-
acc[param.name] = { 'type' => type }
|
313
|
-
acc[param.name]['default_value'] = nil if param.key_type.is_a?(Puppet::Pops::Types::POptionalType)
|
314
|
-
end
|
315
|
-
{
|
316
|
-
'name' => plan_name,
|
317
|
-
'parameters' => parameters
|
318
|
-
}
|
319
|
-
end
|
320
|
-
private :plan_hash
|
321
|
-
|
322
302
|
def get_plan_info(plan_name)
|
323
|
-
|
324
|
-
|
325
|
-
hash = plan_hash(plan_name, plan) if plan
|
326
|
-
hash['module'] = plan.instance_variable_get(:@plan_func).loader.parent.path if plan
|
327
|
-
hash
|
303
|
+
plan_sig = in_bolt_compiler do |compiler|
|
304
|
+
compiler.plan_signature(plan_name)
|
328
305
|
end
|
329
306
|
|
330
|
-
if
|
307
|
+
if plan_sig.nil?
|
331
308
|
raise Bolt::Error.unknown_plan(plan_name)
|
332
309
|
end
|
333
|
-
|
310
|
+
|
311
|
+
mod = plan_sig.instance_variable_get(:@plan_func).loader.parent.path
|
312
|
+
|
313
|
+
# If it's a Puppet language plan, use strings to extract data. The only
|
314
|
+
# way to tell is to check which filename exists in the module.
|
315
|
+
plan_file = plan_name.split('::', 2)[1] || 'init'
|
316
|
+
pp_path = File.join(mod, 'plans', "#{plan_file}.pp")
|
317
|
+
if File.exist?(pp_path)
|
318
|
+
require 'puppet-strings'
|
319
|
+
require 'puppet-strings/yard'
|
320
|
+
PuppetStrings::Yard.setup!
|
321
|
+
YARD::Logger.instance.level = :error
|
322
|
+
YARD.parse(pp_path)
|
323
|
+
|
324
|
+
plan = YARD::Registry.at("puppet_plans::#{plan_name}")
|
325
|
+
|
326
|
+
description = if plan.tag(:summary)
|
327
|
+
plan.tag(:summary).text
|
328
|
+
elsif !plan.docstring.empty?
|
329
|
+
plan.docstring
|
330
|
+
end
|
331
|
+
|
332
|
+
defaults = plan.parameters.reject { |_, value| value.nil? }.to_h
|
333
|
+
parameters = plan.tags(:param).each_with_object({}) do |param, params|
|
334
|
+
name = param.name
|
335
|
+
params[name] = { 'type' => param.types.first }
|
336
|
+
params[name]['default_value'] = defaults[name] if defaults.key?(name)
|
337
|
+
params[name]['description'] = param.text unless param.text.empty?
|
338
|
+
end
|
339
|
+
|
340
|
+
{
|
341
|
+
'name' => plan_name,
|
342
|
+
'description' => description,
|
343
|
+
'parameters' => parameters,
|
344
|
+
'module' => mod
|
345
|
+
}
|
346
|
+
|
347
|
+
# If it's a YAML plan, fall back to limited data
|
348
|
+
else
|
349
|
+
yaml_path = File.join(mod, 'plans', "#{plan_file}.yaml")
|
350
|
+
plan_content = File.read(yaml_path)
|
351
|
+
plan = Bolt::PAL::YamlPlan::Loader.from_string(plan_name, plan_content, yaml_path)
|
352
|
+
|
353
|
+
parameters = plan.parameters.each_with_object({}) do |param, params|
|
354
|
+
name = param.name
|
355
|
+
type_str = case param.type_expr
|
356
|
+
when Puppet::Pops::Types::PTypeReferenceType
|
357
|
+
param.type_expr.type_string
|
358
|
+
when nil
|
359
|
+
'Any'
|
360
|
+
else
|
361
|
+
param.type_expr
|
362
|
+
end
|
363
|
+
params[name] = { 'type' => type_str }
|
364
|
+
params[name]['default_value'] = param.value
|
365
|
+
params[name]['description'] = param.description if param.description
|
366
|
+
end
|
367
|
+
{
|
368
|
+
'name' => plan_name,
|
369
|
+
'description' => plan.description,
|
370
|
+
'parameters' => parameters,
|
371
|
+
'module' => mod
|
372
|
+
}
|
373
|
+
end
|
334
374
|
end
|
335
375
|
|
336
376
|
def convert_plan(plan_path)
|
data/lib/bolt/pal/yaml_plan.rb
CHANGED
@@ -6,16 +6,17 @@ require 'bolt/pal/yaml_plan/step'
|
|
6
6
|
module Bolt
|
7
7
|
class PAL
|
8
8
|
class YamlPlan
|
9
|
-
PLAN_KEYS = Set['parameters', 'steps', 'return', 'version']
|
9
|
+
PLAN_KEYS = Set['parameters', 'steps', 'return', 'version', 'description']
|
10
10
|
VAR_NAME_PATTERN = /\A[a-z_][a-z0-9_]*\z/.freeze
|
11
11
|
|
12
|
-
attr_reader :name, :parameters, :steps, :return
|
12
|
+
attr_reader :name, :parameters, :steps, :return, :description
|
13
13
|
|
14
14
|
def initialize(name, plan)
|
15
15
|
# Top-level plan keys aren't allowed to be Puppet code, so force them
|
16
16
|
# all to strings.
|
17
17
|
plan = Bolt::Util.walk_keys(plan) { |key| stringify(key) }
|
18
18
|
@name = name.freeze
|
19
|
+
@description = stringify(plan['description']) if plan['description']
|
19
20
|
|
20
21
|
params_hash = stringify(plan.fetch('parameters', {}))
|
21
22
|
# Ensure params is a hash
|
@@ -53,7 +53,7 @@ module Bolt
|
|
53
53
|
PuppetVisitor.create_visitor.accept(parse_tree)
|
54
54
|
end
|
55
55
|
|
56
|
-
def self.
|
56
|
+
def self.from_string(name, yaml_string, source_ref)
|
57
57
|
result = parse_plan(yaml_string, source_ref)
|
58
58
|
unless result.is_a?(Hash)
|
59
59
|
type = result.class.name
|
@@ -61,11 +61,14 @@ module Bolt
|
|
61
61
|
end
|
62
62
|
|
63
63
|
begin
|
64
|
-
|
64
|
+
YamlPlan.new(name, result).freeze
|
65
65
|
rescue Bolt::Error => e
|
66
66
|
raise Puppet::ParseError.new(e.message, source_ref)
|
67
67
|
end
|
68
|
+
end
|
68
69
|
|
70
|
+
def self.create(loader, typed_name, source_ref, yaml_string)
|
71
|
+
plan_definition = from_string(typed_name.name, yaml_string, source_ref)
|
69
72
|
created = create_function_class(plan_definition)
|
70
73
|
closure_scope = nil
|
71
74
|
|
@@ -4,7 +4,7 @@ module Bolt
|
|
4
4
|
class PAL
|
5
5
|
class YamlPlan
|
6
6
|
class Parameter
|
7
|
-
attr_reader :name, :value, :type_expr
|
7
|
+
attr_reader :name, :value, :type_expr, :description
|
8
8
|
|
9
9
|
PARAMETER_KEYS = Set['type', 'default', 'description']
|
10
10
|
|
@@ -15,6 +15,7 @@ module Bolt
|
|
15
15
|
@name = param
|
16
16
|
@value = definition['default']
|
17
17
|
@type_expr = Puppet::Pops::Types::TypeParser.singleton.parse(definition['type']) if definition['type']
|
18
|
+
@description = definition['description']
|
18
19
|
end
|
19
20
|
|
20
21
|
def validate_param(param, definition)
|
@@ -48,7 +48,6 @@ module Bolt
|
|
48
48
|
plan_string
|
49
49
|
end
|
50
50
|
|
51
|
-
# Save me from all these rescue statements...
|
52
51
|
def parse_plan
|
53
52
|
begin
|
54
53
|
file_contents = File.read(@plan_path)
|
@@ -57,18 +56,7 @@ module Bolt
|
|
57
56
|
raise Bolt::FileError.new(msg, @plan_path)
|
58
57
|
end
|
59
58
|
|
60
|
-
|
61
|
-
result = Bolt::PAL::YamlPlan::Loader.parse_plan(file_contents, @plan_path)
|
62
|
-
rescue Error => e
|
63
|
-
raise ConvertError.new("Failed to convert yaml plan: #{e.message}", @plan_path)
|
64
|
-
end
|
65
|
-
|
66
|
-
unless result.is_a?(Hash)
|
67
|
-
type = result.class.name
|
68
|
-
raise ArgumentError, "The data loaded from #{source_ref} does not contain an object - its type is #{type}"
|
69
|
-
end
|
70
|
-
|
71
|
-
Bolt::PAL::YamlPlan.new(@modulename, result).freeze
|
59
|
+
Bolt::PAL::YamlPlan::Loader.from_string(@modulename, file_contents, @plan_path)
|
72
60
|
end
|
73
61
|
|
74
62
|
def validate_path
|
data/lib/bolt/plugin.rb
CHANGED
@@ -63,7 +63,7 @@ module Bolt
|
|
63
63
|
if defined?(Puppet)
|
64
64
|
begin
|
65
65
|
compiler = Puppet.lookup(:pal_compiler)
|
66
|
-
rescue Puppet::Context::UndefinedBindingError; end # rubocop:disable Lint/
|
66
|
+
rescue Puppet::Context::UndefinedBindingError; end # rubocop:disable Lint/SuppressedException
|
67
67
|
end
|
68
68
|
|
69
69
|
if compiler
|
data/lib/bolt/plugin/puppetdb.rb
CHANGED
@@ -11,7 +11,8 @@ module Bolt
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
|
14
|
+
TEMPLATE_OPTS = %w[uri name config].freeze
|
15
|
+
PLUGIN_OPTS = %w[_plugin query target_mapping].freeze
|
15
16
|
|
16
17
|
def initialize(pdb_client)
|
17
18
|
@puppetdb_client = pdb_client
|
@@ -45,8 +46,19 @@ module Bolt
|
|
45
46
|
targets = @puppetdb_client.query_certnames(opts['query'])
|
46
47
|
facts = []
|
47
48
|
|
48
|
-
|
49
|
-
|
49
|
+
template = opts.delete('target_mapping') || {}
|
50
|
+
|
51
|
+
keys = Set.new(TEMPLATE_OPTS) & opts.keys
|
52
|
+
unless keys.empty?
|
53
|
+
raise Bolt::ValidationError, "PuppetDB plugin expects keys #{keys.to_a} to be set under 'target_mapping'"
|
54
|
+
end
|
55
|
+
|
56
|
+
keys = Set.new(opts.keys) - PLUGIN_OPTS
|
57
|
+
unless keys.empty?
|
58
|
+
raise Bolt::ValidationError, "Unknown keys in PuppetDB plugin: #{keys.to_a}"
|
59
|
+
end
|
60
|
+
|
61
|
+
Bolt::Util.walk_vals(template) do |value|
|
50
62
|
# This is done in parts instead of in place so that we only need to
|
51
63
|
# make one puppetDB query
|
52
64
|
if value.is_a?(String)
|
@@ -61,7 +73,7 @@ module Bolt
|
|
61
73
|
|
62
74
|
targets.map do |certname|
|
63
75
|
target_data = fact_values[certname]
|
64
|
-
target = resolve_facts(
|
76
|
+
target = resolve_facts(template, certname, target_data) || {}
|
65
77
|
target['uri'] = certname unless target['uri'] || target['name']
|
66
78
|
|
67
79
|
target
|
data/lib/bolt/util.rb
CHANGED
@@ -176,7 +176,7 @@ module Bolt
|
|
176
176
|
rescue TypeError
|
177
177
|
# unclonable (TrueClass, Fixnum, ...)
|
178
178
|
cloned[obj.object_id] = obj
|
179
|
-
|
179
|
+
obj
|
180
180
|
else
|
181
181
|
cloned[obj.object_id] = cl
|
182
182
|
cloned[cl.object_id] = cl
|
@@ -195,7 +195,7 @@ module Bolt
|
|
195
195
|
cl.instance_variable_set(var, v_cl)
|
196
196
|
end
|
197
197
|
|
198
|
-
|
198
|
+
cl
|
199
199
|
end
|
200
200
|
end
|
201
201
|
|
data/lib/bolt/version.rb
CHANGED
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.40.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-12-02 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: 1.8.1
|
187
|
+
- !ruby/object:Gem::Dependency
|
188
|
+
name: puppet-strings
|
189
|
+
requirement: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - "~>"
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '2.3'
|
194
|
+
type: :runtime
|
195
|
+
prerelease: false
|
196
|
+
version_requirements: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - "~>"
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '2.3'
|
187
201
|
- !ruby/object:Gem::Dependency
|
188
202
|
name: r10k
|
189
203
|
requirement: !ruby/object:Gem::Requirement
|