bolt 2.22.0 → 2.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.

Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +1 -1
  3. data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +2 -1
  4. data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +1 -1
  5. data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +12 -6
  6. data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +1 -1
  7. data/bolt-modules/out/lib/puppet/functions/out/message.rb +1 -1
  8. data/exe/bolt +1 -0
  9. data/guides/inventory.txt +19 -0
  10. data/guides/project.txt +22 -0
  11. data/lib/bolt/analytics.rb +8 -8
  12. data/lib/bolt/applicator.rb +6 -6
  13. data/lib/bolt/bolt_option_parser.rb +47 -24
  14. data/lib/bolt/catalog.rb +4 -2
  15. data/lib/bolt/cli.rb +97 -78
  16. data/lib/bolt/config.rb +46 -24
  17. data/lib/bolt/config/options.rb +9 -6
  18. data/lib/bolt/executor.rb +10 -8
  19. data/lib/bolt/inventory.rb +8 -1
  20. data/lib/bolt/inventory/group.rb +4 -4
  21. data/lib/bolt/inventory/inventory.rb +1 -1
  22. data/lib/bolt/inventory/target.rb +1 -1
  23. data/lib/bolt/logger.rb +12 -6
  24. data/lib/bolt/outputter.rb +56 -0
  25. data/lib/bolt/outputter/human.rb +10 -9
  26. data/lib/bolt/outputter/json.rb +11 -4
  27. data/lib/bolt/outputter/logger.rb +3 -3
  28. data/lib/bolt/outputter/rainbow.rb +15 -0
  29. data/lib/bolt/pal.rb +9 -19
  30. data/lib/bolt/pal/yaml_plan/evaluator.rb +2 -2
  31. data/lib/bolt/pal/yaml_plan/transpiler.rb +11 -3
  32. data/lib/bolt/plugin/prompt.rb +3 -3
  33. data/lib/bolt/plugin/puppetdb.rb +1 -1
  34. data/lib/bolt/project.rb +32 -19
  35. data/lib/bolt/project_migrate.rb +138 -0
  36. data/lib/bolt/puppetdb/client.rb +1 -1
  37. data/lib/bolt/puppetdb/config.rb +1 -1
  38. data/lib/bolt/r10k_log_proxy.rb +1 -1
  39. data/lib/bolt/rerun.rb +1 -1
  40. data/lib/bolt/result.rb +8 -0
  41. data/lib/bolt/shell.rb +1 -1
  42. data/lib/bolt/shell/bash.rb +7 -7
  43. data/lib/bolt/task.rb +1 -1
  44. data/lib/bolt/transport/base.rb +1 -1
  45. data/lib/bolt/transport/docker/connection.rb +10 -10
  46. data/lib/bolt/transport/local/connection.rb +3 -3
  47. data/lib/bolt/transport/orch.rb +3 -3
  48. data/lib/bolt/transport/ssh.rb +1 -1
  49. data/lib/bolt/transport/ssh/connection.rb +6 -6
  50. data/lib/bolt/transport/ssh/exec_connection.rb +5 -5
  51. data/lib/bolt/transport/winrm.rb +1 -1
  52. data/lib/bolt/transport/winrm/connection.rb +9 -9
  53. data/lib/bolt/util.rb +2 -2
  54. data/lib/bolt/util/puppet_log_level.rb +4 -3
  55. data/lib/bolt/version.rb +1 -1
  56. data/lib/bolt_server/base_config.rb +1 -1
  57. data/lib/bolt_server/file_cache.rb +1 -1
  58. data/lib/bolt_server/pe/pal.rb +1 -1
  59. data/lib/bolt_server/transport_app.rb +76 -0
  60. data/lib/bolt_spec/plans.rb +1 -1
  61. data/lib/bolt_spec/plans/action_stubs.rb +1 -1
  62. data/lib/bolt_spec/run.rb +3 -0
  63. data/libexec/apply_catalog.rb +2 -2
  64. data/libexec/bolt_catalog +1 -1
  65. data/libexec/custom_facts.rb +1 -1
  66. data/libexec/query_resources.rb +1 -1
  67. metadata +9 -12
@@ -176,7 +176,9 @@ module Bolt
176
176
  description: "A map of configuration for the logfile output. Under `log`, you can configure log options "\
177
177
  "for `console` and add configuration for individual log files, such as "\
178
178
  "`~/.puppetlabs/bolt/debug.log`. Individual log files must be valid filepaths. If the log "\
179
- "file does not exist, then Bolt will create it before logging information.",
179
+ "file does not exist, then Bolt will create it before logging information. Set the value to "\
180
+ "`disable` to remove a log file defined at an earlier level of the config hierarchy. By "\
181
+ "default, Bolt logs to a bolt-debug.log file in the Bolt project directory.",
180
182
  type: Hash,
181
183
  properties: {
182
184
  "console" => {
@@ -186,15 +188,16 @@ module Bolt
186
188
  "level" => {
187
189
  description: "The type of information to log.",
188
190
  type: String,
189
- enum: %w[debug error info notice warn fatal any],
190
- _default: "warn for console, notice for file"
191
+ enum: %w[trace debug error info warn fatal any],
192
+ _default: "warn"
191
193
  }
192
194
  }
193
195
  }
194
196
  },
195
197
  additionalProperties: {
196
198
  description: "Configuration for the logfile output.",
197
- type: Hash,
199
+ type: [String, Hash],
200
+ enum: ['disable'],
198
201
  properties: {
199
202
  "append" => {
200
203
  description: "Whether to append output to an existing log file.",
@@ -204,8 +207,8 @@ module Bolt
204
207
  "level" => {
205
208
  description: "The type of information to log.",
206
209
  type: String,
207
- enum: %w[debug error info notice warn fatal any],
208
- _default: "warn for console, notice for file"
210
+ enum: %w[trace debug error info warn fatal any],
211
+ _default: "warn"
209
212
  }
210
213
  }
211
214
  },
@@ -40,7 +40,7 @@ module Bolt
40
40
  require 'concurrent'
41
41
 
42
42
  @analytics = analytics
43
- @logger = Logging.logger[self]
43
+ @logger = Bolt::Logger.logger(self)
44
44
 
45
45
  @transports = Bolt::TRANSPORTS.each_with_object({}) do |(key, val), coll|
46
46
  coll[key.to_s] = if key == :remote
@@ -56,11 +56,12 @@ module Bolt
56
56
  @reported_transports = Set.new
57
57
  @subscribers = {}
58
58
  @publisher = Concurrent::SingleThreadExecutor.new
59
+ @publisher.post { Thread.current[:name] = 'event-publisher' }
59
60
 
60
61
  @noop = noop
61
62
  @run_as = nil
62
63
  @pool = if concurrency > 0
63
- Concurrent::ThreadPoolExecutor.new(max_threads: concurrency)
64
+ Concurrent::ThreadPoolExecutor.new(name: 'exec', max_threads: concurrency)
64
65
  else
65
66
  Concurrent.global_immediate_executor
66
67
  end
@@ -125,6 +126,7 @@ module Bolt
125
126
  # Pass this argument through to avoid retaining a reference to a
126
127
  # local variable that will change on the next iteration of the loop.
127
128
  @pool.post(batch_promises) do |result_promises|
129
+ Thread.current[:name] ||= Thread.current.name
128
130
  results = yield transport, batch
129
131
  Array(results).each do |result|
130
132
  result_promises[result.target].set(result)
@@ -241,7 +243,7 @@ module Bolt
241
243
 
242
244
  @analytics&.event('Plan', 'yaml', plan_steps: steps, return_type: return_type)
243
245
  rescue StandardError => e
244
- @logger.debug { "Failed to submit analytics event: #{e.message}" }
246
+ @logger.trace { "Failed to submit analytics event: #{e.message}" }
245
247
  end
246
248
 
247
249
  def with_node_logging(description, batch)
@@ -381,19 +383,19 @@ module Bolt
381
383
  end
382
384
 
383
385
  def prompt(prompt, options)
384
- unless STDIN.tty?
386
+ unless $stdin.tty?
385
387
  raise Bolt::Error.new('STDIN is not a tty, unable to prompt', 'bolt/no-tty-error')
386
388
  end
387
389
 
388
- STDERR.print("#{prompt}: ")
390
+ $stderr.print("#{prompt}: ")
389
391
 
390
392
  value = if options[:sensitive]
391
- STDIN.noecho(&:gets).to_s.chomp
393
+ $stdin.noecho(&:gets).to_s.chomp
392
394
  else
393
- STDIN.gets.to_s.chomp
395
+ $stdin.gets.to_s.chomp
394
396
  end
395
397
 
396
- STDERR.puts if options[:sensitive]
398
+ $stderr.puts if options[:sensitive]
397
399
 
398
400
  value
399
401
  end
@@ -46,10 +46,13 @@ module Bolt
46
46
  end
47
47
 
48
48
  def self.from_config(config, plugins)
49
+ logger = Logging.logger[self]
50
+
49
51
  if ENV.include?(ENVIRONMENT_VAR)
50
52
  begin
51
53
  data = YAML.safe_load(ENV[ENVIRONMENT_VAR])
52
54
  raise Bolt::ParseError, "Could not parse inventory from $#{ENVIRONMENT_VAR}" unless data.is_a?(Hash)
55
+ logger.debug("Loaded inventory from environment variable #{ENVIRONMENT_VAR}")
53
56
  rescue Psych::Exception
54
57
  raise Bolt::ParseError, "Could not parse inventory from $#{ENVIRONMENT_VAR}"
55
58
  end
@@ -57,8 +60,12 @@ module Bolt
57
60
  data = if config.inventoryfile
58
61
  Bolt::Util.read_yaml_hash(config.inventoryfile, 'inventory')
59
62
  else
60
- Bolt::Util.read_optional_yaml_hash(config.default_inventoryfile, 'inventory')
63
+ i = Bolt::Util.read_optional_yaml_hash(config.default_inventoryfile, 'inventory')
64
+ logger.debug("Loaded inventory from #{config.default_inventoryfile}") if i
65
+ i
61
66
  end
67
+ # This avoids rubocop complaining about identical conditionals
68
+ logger.debug("Loaded inventory from #{config.inventoryfile}") if config.inventoryfile
62
69
  end
63
70
 
64
71
  # Resolve plugin references from transport config
@@ -19,7 +19,7 @@ module Bolt
19
19
  CONFIG_KEYS = Bolt::Config::INVENTORY_OPTIONS.keys
20
20
 
21
21
  def initialize(input, plugins)
22
- @logger = Logging.logger[self]
22
+ @logger = Bolt::Logger.logger(self)
23
23
  @plugins = plugins
24
24
 
25
25
  input = @plugins.resolve_top_level_references(input) if @plugins.reference?(input)
@@ -119,7 +119,7 @@ module Bolt
119
119
  end
120
120
 
121
121
  if contains_target?(t_name)
122
- @logger.warn("Ignoring duplicate target in #{@name}: #{target}")
122
+ @logger.debug("Ignoring duplicate target in #{@name}: #{target}")
123
123
  return
124
124
  end
125
125
 
@@ -200,14 +200,14 @@ module Bolt
200
200
  # If this is an alias for an existing target, then add it to this group
201
201
  elsif (canonical_name = aliases[string_target])
202
202
  if contains_target?(canonical_name)
203
- @logger.warn("Ignoring duplicate target in #{@name}: #{canonical_name}")
203
+ @logger.debug("Ignoring duplicate target in #{@name}: #{canonical_name}")
204
204
  else
205
205
  @unresolved_targets[canonical_name] = { 'name' => canonical_name }
206
206
  end
207
207
  # If it's not the name or alias of an existing target, then make a
208
208
  # new target using the string as the URI
209
209
  elsif contains_target?(string_target)
210
- @logger.warn("Ignoring duplicate target in #{@name}: #{string_target}")
210
+ @logger.debug("Ignoring duplicate target in #{@name}: #{string_target}")
211
211
  else
212
212
  @unresolved_targets[string_target] = { 'uri' => string_target }
213
213
  end
@@ -16,7 +16,7 @@ module Bolt
16
16
 
17
17
  # TODO: Pass transport config instead of config object
18
18
  def initialize(data, transport, transports, plugins)
19
- @logger = Logging.logger[self]
19
+ @logger = Bolt::Logger.logger(self)
20
20
  @data = data || {}
21
21
  @transport = transport
22
22
  @config = transports
@@ -13,7 +13,7 @@ module Bolt
13
13
  raise Bolt::Inventory::ValidationError.new("Target must have either a name or uri", nil)
14
14
  end
15
15
 
16
- @logger = Logging.logger[inventory]
16
+ @logger = Bolt::Logger.logger(inventory)
17
17
 
18
18
  # If the target isn't mentioned by any groups, it won't have a uri or
19
19
  # name and we will use the target_name as both
@@ -14,13 +14,12 @@ module Bolt
14
14
  # redefs, so skip it if it's already been initialized
15
15
  return if Logging.initialized?
16
16
 
17
- Logging.init :debug, :info, :notice, :warn, :error, :fatal, :any
17
+ Logging.init :trace, :debug, :info, :notice, :warn, :error, :fatal, :any
18
18
  @mutex = Mutex.new
19
19
 
20
20
  Logging.color_scheme(
21
21
  'bolt',
22
22
  lines: {
23
- notice: :green,
24
23
  warn: :yellow,
25
24
  error: :red,
26
25
  fatal: %i[white on_red]
@@ -29,7 +28,7 @@ module Bolt
29
28
  end
30
29
 
31
30
  def self.configure(destinations, color)
32
- root_logger = Logging.logger[:root]
31
+ root_logger = Bolt::Logger.logger(:root)
33
32
 
34
33
  root_logger.add_appenders Logging.appenders.stderr(
35
34
  'console',
@@ -67,6 +66,13 @@ module Bolt
67
66
  end
68
67
  end
69
68
 
69
+ # A helper to ensure the Logging library is always initialized with our
70
+ # custom log levels before retrieving a Logger instance.
71
+ def self.logger(name)
72
+ initialize_logging
73
+ Logging.logger[name]
74
+ end
75
+
70
76
  def self.analytics=(analytics)
71
77
  @analytics = analytics
72
78
  end
@@ -81,7 +87,7 @@ module Bolt
81
87
 
82
88
  def self.default_layout
83
89
  Logging.layouts.pattern(
84
- pattern: '%d %-6l %c: %m\n',
90
+ pattern: '%d %-6l [%T] [%c] %m\n',
85
91
  date_pattern: '%Y-%m-%dT%H:%M:%S.%6N'
86
92
  )
87
93
  end
@@ -91,7 +97,7 @@ module Bolt
91
97
  end
92
98
 
93
99
  def self.default_file_level
94
- :notice
100
+ :warn
95
101
  end
96
102
 
97
103
  # Explicitly check the log level names instead of the log level number, as levels
@@ -111,7 +117,7 @@ module Bolt
111
117
  def self.warn_once(type, msg)
112
118
  @mutex.synchronize {
113
119
  @warnings ||= []
114
- @logger ||= Logging.logger[self]
120
+ @logger ||= Bolt::Logger.logger(self)
115
121
  unless @warnings.include?(type)
116
122
  @logger.warn(msg)
117
123
  @warnings << type
@@ -21,6 +21,62 @@ module Bolt
21
21
  @trace = trace
22
22
  @stream = stream
23
23
  end
24
+
25
+ def indent(indent, string)
26
+ indent = ' ' * indent
27
+ string.gsub(/^/, indent.to_s)
28
+ end
29
+
30
+ def print_message_event(event)
31
+ print_message(stringify(event[:message]))
32
+ end
33
+
34
+ def print_message
35
+ raise NotImplementedError, "print_message() must be implemented by the outputter class"
36
+ end
37
+
38
+ def stringify(message)
39
+ formatted = format_message(message)
40
+ if formatted.is_a?(Hash) || formatted.is_a?(Array)
41
+ ::JSON.pretty_generate(formatted)
42
+ else
43
+ formatted
44
+ end
45
+ end
46
+
47
+ def format_message(message)
48
+ case message
49
+ when Array
50
+ message.map { |item| format_message(item) }
51
+ when Bolt::ApplyResult
52
+ format_apply_result(message)
53
+ when Bolt::Result, Bolt::ResultSet
54
+ # This is equivalent to to_s, but formattable
55
+ message.to_data
56
+ when Bolt::RunFailure
57
+ formatted_resultset = message.result_set.to_data
58
+ message.to_h.merge('result_set' => formatted_resultset)
59
+ when Hash
60
+ message.each_with_object({}) do |(k, v), h|
61
+ h[format_message(k)] = format_message(v)
62
+ end
63
+ when Integer, Float, NilClass
64
+ message
65
+ else
66
+ message.to_s
67
+ end
68
+ end
69
+
70
+ def format_apply_result(result)
71
+ logs = result.resource_logs&.map do |log|
72
+ # Omit low-level info/debug messages
73
+ next if %w[info debug].include?(log['level'])
74
+ indent(2, format_log(log))
75
+ end
76
+ hash = result.to_data
77
+ hash['logs'] = logs unless logs.empty?
78
+ hash
79
+ end
24
80
  end
25
81
  end
26
82
 
@@ -27,11 +27,6 @@ module Bolt
27
27
  end
28
28
  end
29
29
 
30
- def indent(indent, string)
31
- indent = ' ' * indent
32
- string.gsub(/^/, indent.to_s)
33
- end
34
-
35
30
  def remove_trail(string)
36
31
  string.sub(/\s\z/, '')
37
32
  end
@@ -291,6 +286,16 @@ module Bolt
291
286
  "details and parameters for a specific plan.")
292
287
  end
293
288
 
289
+ def print_topics(topics)
290
+ print_message("Available topics are:")
291
+ print_message(topics.join("\n"))
292
+ print_message("\nUse `bolt guide <topic>` to view a specific guide.")
293
+ end
294
+
295
+ def print_guide(guide, _topic)
296
+ @stream.puts(guide)
297
+ end
298
+
294
299
  def print_module_list(module_list)
295
300
  module_list.each do |path, modules|
296
301
  if (mod = modules.find { |m| m[:internal_module_group] })
@@ -372,10 +377,6 @@ module Bolt
372
377
  end
373
378
  end
374
379
 
375
- def print_message_event(event)
376
- print_message(event[:message])
377
- end
378
-
379
380
  def fatal_error(err)
380
381
  @stream.puts(colorize(:red, err.message))
381
382
  if err.is_a? Bolt::RunFailure
@@ -83,6 +83,17 @@ module Bolt
83
83
  @stream.puts result.to_json
84
84
  end
85
85
 
86
+ def print_topics(topics)
87
+ print_table('topics' => topics)
88
+ end
89
+
90
+ def print_guide(guide, topic)
91
+ @stream.puts({
92
+ 'topic' => topic,
93
+ 'guide' => guide
94
+ }.to_json)
95
+ end
96
+
86
97
  def print_puppetfile_result(success, puppetfile, moduledir)
87
98
  @stream.puts({ "success": success,
88
99
  "puppetfile": puppetfile,
@@ -121,10 +132,6 @@ module Bolt
121
132
  @stream.puts '}' if @object_open
122
133
  end
123
134
 
124
- def print_message_event(event)
125
- print_message(event[:message])
126
- end
127
-
128
135
  def print_message(message)
129
136
  $stderr.puts(message)
130
137
  end
@@ -7,7 +7,7 @@ module Bolt
7
7
  class Logger < Bolt::Outputter
8
8
  def initialize(verbose, trace)
9
9
  super(false, verbose, trace)
10
- @logger = Logging.logger[self]
10
+ @logger = Bolt::Logger.logger(self)
11
11
  end
12
12
 
13
13
  def handle_event(event)
@@ -40,13 +40,13 @@ module Bolt
40
40
 
41
41
  def log_plan_start(event)
42
42
  plan = event[:plan]
43
- @logger.notice("Starting: plan #{plan}")
43
+ @logger.info("Starting: plan #{plan}")
44
44
  end
45
45
 
46
46
  def log_plan_finish(event)
47
47
  plan = event[:plan]
48
48
  duration = event[:duration]
49
- @logger.notice("Finished: plan #{plan} in #{duration.round(2)} sec")
49
+ @logger.info("Finished: plan #{plan} in #{duration.round(2)} sec")
50
50
  end
51
51
  end
52
52
  end
@@ -86,6 +86,21 @@ module Bolt
86
86
  total_msg << " in #{duration_to_string(elapsed_time)}" unless elapsed_time.nil?
87
87
  @stream.puts colorize(:rainbow, total_msg)
88
88
  end
89
+
90
+ def print_guide(guide, _topic)
91
+ @stream.puts colorize(:rainbow, guide)
92
+ end
93
+
94
+ def print_topics(topics)
95
+ content = String.new("Available topics are:\n")
96
+ content += topics.join("\n")
97
+ content += "\n\nUse `bolt guide <topic>` to view a specific guide."
98
+ @stream.puts colorize(:rainbow, content)
99
+ end
100
+
101
+ def print_message(message)
102
+ @stream.puts colorize(:rainbow, message)
103
+ end
89
104
  end
90
105
  end
91
106
  end
@@ -48,7 +48,7 @@ module Bolt
48
48
  end
49
49
  end
50
50
 
51
- attr_reader :modulepath
51
+ attr_reader :modulepath, :user_modulepath
52
52
 
53
53
  def initialize(modulepath, hiera_config, resource_types, max_compiles = Etc.nprocessors,
54
54
  trusted_external = nil, apply_settings = {}, project = nil)
@@ -56,7 +56,7 @@ module Bolt
56
56
  # is safe and in practice only happens in tests
57
57
  self.class.load_puppet
58
58
 
59
- @original_modulepath = modulepath
59
+ @user_modulepath = modulepath
60
60
  @modulepath = [BOLTLIB_PATH, *modulepath, MODULES_PATH]
61
61
  @hiera_config = hiera_config
62
62
  @trusted_external = trusted_external
@@ -65,9 +65,9 @@ module Bolt
65
65
  @resource_types = resource_types
66
66
  @project = project
67
67
 
68
- @logger = Logging.logger[self]
68
+ @logger = Bolt::Logger.logger(self)
69
69
  if modulepath && !modulepath.empty?
70
- @logger.info("Loading modules from #{@modulepath.join(File::PATH_SEPARATOR)}")
70
+ @logger.debug("Loading modules from #{@modulepath.join(File::PATH_SEPARATOR)}")
71
71
  end
72
72
 
73
73
  @loaded = false
@@ -76,7 +76,7 @@ module Bolt
76
76
  # Puppet logging is global so this is class method to avoid confusion
77
77
  def self.configure_logging
78
78
  Puppet::Util::Log.destinations.clear
79
- Puppet::Util::Log.newdestination(Logging.logger['Puppet'])
79
+ Puppet::Util::Log.newdestination(Bolt::Logger.logger('Puppet'))
80
80
  # Defer all log level decisions to the Logging library by telling Puppet
81
81
  # to log everything
82
82
  Puppet.settings[:log_level] = 'debug'
@@ -149,15 +149,9 @@ module Bolt
149
149
  setup
150
150
  r = Puppet::Pal.in_tmp_environment('bolt', modulepath: @modulepath, facts: {}) do |pal|
151
151
  # Only load the project if it a) exists, b) has a name it can be loaded with
152
- bolt_project = @project if @project&.name
153
- # Puppet currently won't receive the project unless it is a named project. Since
154
- # the download_file plan function needs access to the project path, add it to the
155
- # context.
156
- bolt_project_data = @project
157
- Puppet.override(bolt_project: bolt_project,
158
- bolt_project_data: bolt_project_data,
152
+ Puppet.override(bolt_project: @project,
159
153
  yaml_plan_instantiator: Bolt::PAL::YamlPlan::Loader) do
160
- pal.with_script_compiler do |compiler|
154
+ pal.with_script_compiler(set_local_facts: false) do |compiler|
161
155
  alias_types(compiler)
162
156
  register_resource_types(Puppet.lookup(:loaders)) if @resource_types
163
157
  begin
@@ -208,7 +202,7 @@ module Bolt
208
202
  # Skip syncing built-in plugins, since we vendor some Puppet 6
209
203
  # versions of "core" types, which are already present on the agent,
210
204
  # but may cause issues on Puppet 5 agents.
211
- @original_modulepath,
205
+ @user_modulepath,
212
206
  @project,
213
207
  pdb_client,
214
208
  @hiera_config,
@@ -278,10 +272,6 @@ module Bolt
278
272
  end
279
273
  end
280
274
 
281
- def list_modulepath
282
- @modulepath - [BOLTLIB_PATH, MODULES_PATH]
283
- end
284
-
285
275
  def parse_params(type, object_name, params)
286
276
  in_bolt_compiler do |compiler|
287
277
  case type
@@ -413,7 +403,7 @@ module Bolt
413
403
  end
414
404
  params[name] = { 'type' => type_str }
415
405
  params[name]['sensitive'] = param.type_expr.instance_of?(Puppet::Pops::Types::PSensitiveType)
416
- params[name]['default_value'] = param.value
406
+ params[name]['default_value'] = param.value unless param.value.nil?
417
407
  params[name]['description'] = param.description if param.description
418
408
  end
419
409
  {