bolt 0.21.2 → 0.21.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19cf0dd944021e5b7255b245987961c4155b4ea9400e5d65ad384342fa094a0d
4
- data.tar.gz: 3755fd0a3e63d7e28e82b08e255953c51b0b539ceb3e180a69930a6cdddc1eb2
3
+ metadata.gz: bfc1d47b6d45382d603a222c1aa4a5066a560e4439799afc00a15b44002497fb
4
+ data.tar.gz: 9e1c7c4c69d255092849484da518a6c9c02115917f8f5f3475ee8669b322bf70
5
5
  SHA512:
6
- metadata.gz: 84db88c85867ef1a27f4a726f2672ba1b78d453cec47f0f003326079c777b398039f5516e2c1f33697e7ac19e9d861b75d4767cb9512bf7e9bb8dbabe2ad19a1
7
- data.tar.gz: 0b465783458691bbcb78f1f52eba1b4e7b04c2840e1c06ea24f6ddf4947d6daf5d664b21d4d77062d88eaeace4f224edb5bb1dfada97131fd0e1356d330b9846
6
+ metadata.gz: 29dd0f53e14ef2d7787e59ddf121f3a96a27c7b0810b3971a55a377c2e0f5d0996f78359e685459edbafea7a78e2e284b454027e22906edde2790bc9452ed23b
7
+ data.tar.gz: cb7268a4c9de0d2b8fd99649d112276c8542275b8f3ce7e134f7b1b2a041cb688537e13ce98a607753c597eec028ff1fb29c09ad1b18ead6aa291014e4dfb91d
@@ -17,14 +17,8 @@ Puppet::Functions.create_function(:puppetdb_fact) do
17
17
  end
18
18
 
19
19
  def puppetdb_fact(certnames)
20
- unless Puppet[:tasks]
21
- raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
22
- Puppet::Pops::Issues::TASK_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, operation: 'puppetdb_fact'
23
- )
24
- end
25
-
26
20
  puppetdb_client = Puppet.lookup(:bolt_pdb_client) { nil }
27
- unless puppetdb_client && Puppet.features.bolt?
21
+ unless puppetdb_client
28
22
  raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
29
23
  Puppet::Pops::Issues::TASK_MISSING_BOLT, action: _('query facts from puppetdb')
30
24
  )
@@ -16,7 +16,7 @@ Puppet::Functions.create_function(:puppetdb_query) do
16
16
 
17
17
  def make_query(query)
18
18
  puppetdb_client = Puppet.lookup(:bolt_pdb_client) { nil }
19
- unless Puppet[:tasks] && puppetdb_client && Puppet.features.bolt?
19
+ unless puppetdb_client
20
20
  raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
21
21
  Puppet::Pops::Issues::TASK_MISSING_BOLT, action: _('query facts from puppetdb')
22
22
  )
@@ -13,6 +13,7 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
13
13
  scope_param
14
14
  param 'String', :plan_name
15
15
  optional_param 'Hash', :named_args
16
+ return_type 'Boltlib::PlanResult'
16
17
  end
17
18
 
18
19
  def run_plan(scope, plan_name, named_args = {})
@@ -35,6 +36,9 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
35
36
  executor.report_function_call('run_plan')
36
37
  end
37
38
 
39
+ # Report bundled content, this should capture plans run from both CLI and Plans
40
+ executor.report_bundled_content('Plan', plan_name)
41
+
38
42
  params = named_args.reject { |k, _| k.start_with?('_') }
39
43
 
40
44
  loaders = closure_scope.compiler.loaders
@@ -86,6 +86,9 @@ Puppet::Functions.create_function(:run_task) do
86
86
  executor.report_function_call('run_task')
87
87
  end
88
88
 
89
+ # Report bundled content, this should capture tasks run from both CLI and Plans
90
+ executor.report_bundled_content('Task', task_name)
91
+
89
92
  # Ensure that given targets are all Target instances
90
93
  targets = inventory.get_targets(targets)
91
94
 
@@ -1,4 +1,4 @@
1
- # A Planresult describes the supported return values of a plan. It
1
+ # A PlanResult describes the supported return values of a plan. It
2
2
  # should be used as the return type of functions that run plans and return the
3
3
  # results.
4
4
 
@@ -24,7 +24,6 @@ module Bolt
24
24
 
25
25
  def self.build_client
26
26
  logger = Logging.logger[self]
27
-
28
27
  config_file = File.expand_path('~/.puppetlabs/bolt/analytics.yaml')
29
28
  config = load_config(config_file)
30
29
 
@@ -2,17 +2,72 @@
2
2
 
3
3
  require 'json'
4
4
  require 'open3'
5
+ require 'concurrent'
5
6
 
6
7
  module Bolt
7
8
  Task = Struct.new(:name, :implementations, :input_method)
8
9
 
9
10
  class Applicator
10
- def initialize(inventory, executor)
11
+ def initialize(inventory, executor, modulepath, pdb_config, hiera_config, max_compiles)
11
12
  @inventory = inventory
12
13
  @executor = executor
14
+ @modulepath = modulepath
15
+ @pdb_config = pdb_config
16
+ @hiera_config = hiera_config ? validate_hiera_config(hiera_config) : nil
17
+
18
+ @pool = Concurrent::ThreadPoolExecutor.new(max_threads: max_compiles)
19
+ end
20
+
21
+ private def libexec
22
+ @libexec ||= File.join(Gem::Specification.find_by_name('bolt').gem_dir, 'libexec')
23
+ end
24
+
25
+ def catalog_apply_task
26
+ @catalog_apply_task ||= begin
27
+ path = File.join(libexec, 'apply_catalog.rb')
28
+ impl = { 'name' => 'apply_catalog.rb', 'path' => path, 'requirements' => [], 'supports_noop' => true }
29
+ Task.new('apply_catalog', [impl], 'stdin')
30
+ end
31
+ end
32
+
33
+ def compile(target, ast, plan_vars)
34
+ trusted = Puppet::Context::TrustedInformation.new('local', target.host, {})
35
+
36
+ catalog_input = {
37
+ code_ast: ast,
38
+ modulepath: @modulepath,
39
+ pdb_config: @pdb_config,
40
+ hiera_config: @hiera_config,
41
+ target: {
42
+ name: target.host,
43
+ facts: @inventory.facts(target),
44
+ variables: @inventory.vars(target).merge(plan_vars),
45
+ trusted: trusted.to_h
46
+ }
47
+ }
48
+
49
+ bolt_catalog_exe = File.join(libexec, 'bolt_catalog')
50
+
51
+ old_path = ENV['PATH']
52
+ ENV['PATH'] = "#{RbConfig::CONFIG['bindir']}#{File::PATH_SEPARATOR}#{old_path}"
53
+ out, err, stat = Open3.capture3('ruby', bolt_catalog_exe, 'compile', stdin_data: catalog_input.to_json)
54
+ ENV['PATH'] = old_path
55
+
56
+ raise ApplyError.new(target.to_s, err) unless stat.success?
57
+ JSON.parse(out)
13
58
  end
14
59
 
15
- def apply(args, apply_body, _scope)
60
+ def validate_hiera_config(hiera_config)
61
+ if File.exist?(File.path(hiera_config))
62
+ data = File.open(File.path(hiera_config), "r:UTF-8") { |f| YAML.safe_load(f.read) }
63
+ unless data['version'] == 5
64
+ raise ApplyError.new("All Targets", "Hiera v5 is required.")
65
+ end
66
+ hiera_config
67
+ end
68
+ end
69
+
70
+ def apply(args, apply_body, scope)
16
71
  raise(ArgumentError, 'apply requires a TargetSpec') if args.empty?
17
72
  type0 = Puppet.lookup(:pal_script_compiler).type('TargetSpec')
18
73
  Puppet::Pal.assert_type(type0, args[0], 'apply targets')
@@ -24,33 +79,36 @@ module Bolt
24
79
  params = args[1]
25
80
  end
26
81
 
82
+ # collect plan vars and merge them over target vars
83
+ plan_vars = scope.to_hash
84
+ %w[trusted server_facts facts].each { |k| plan_vars.delete(k) }
85
+
27
86
  targets = @inventory.get_targets(args[0])
28
87
  ast = Puppet::Pops::Serialization::ToDataConverter.convert(apply_body, rich_data: true, symbol_to_string: true)
29
- results = targets.map do |target|
30
- catalog_input = {
31
- code_ast: ast,
32
- modulepath: [],
33
- target: {
34
- name: target.host,
35
- facts: @inventory.facts(target),
36
- variables: @inventory.vars(target)
37
- }
38
- }
88
+ notify = proc { |_| nil }
39
89
 
40
- libexec = File.join(Gem::Specification.find_by_name('bolt').gem_dir, 'libexec')
90
+ @executor.log_action('apply catalog', targets) do
91
+ futures = targets.map do |target|
92
+ Concurrent::Future.execute(executor: @pool) do
93
+ @executor.with_node_logging("Compiling manifest block", [target]) do
94
+ compile(target, ast, plan_vars)
95
+ end
96
+ end
97
+ end
41
98
 
42
- bolt_catalog_exe = File.join(libexec, 'bolt_catalog')
43
- out, err, stat = Open3.capture3(bolt_catalog_exe, 'compile', stdin_data: catalog_input.to_json)
44
- raise ApplyError.new(target.to_s, err) unless stat.success?
45
- catalog = JSON.parse(out)
99
+ result_promises = targets.zip(futures).flat_map do |target, future|
100
+ @executor.queue_execute([target]) do |transport, batch|
101
+ @executor.with_node_logging("Applying manifest block", batch) do
102
+ arguments = params.clone
103
+ arguments['catalog'] = future.value
104
+ raise future.reason if future.rejected?
105
+ transport.batch_task(batch, catalog_apply_task, arguments, {}, &notify)
106
+ end
107
+ end
108
+ end
46
109
 
47
- path = File.join(libexec, 'apply_catalog.rb')
48
- impl = { 'name' => 'apply_catalog.rb', 'path' => path, 'requirements' => [], 'supports_noop' => true }
49
- task = Task.new('apply_catalog', [impl], 'stdin')
50
- params['catalog'] = catalog
51
- @executor.run_task([target], task, params, '_description' => 'apply catalog')
110
+ @executor.await_results(result_promises)
52
111
  end
53
- ResultSet.new results.reduce([]) { |result, result_set| result + result_set.results }
54
112
  end
55
113
  end
56
114
  end
@@ -183,6 +183,10 @@ Available options are:
183
183
  'Maximum number of simultaneous connections (default: 100)') do |concurrency|
184
184
  @options[:concurrency] = concurrency
185
185
  end
186
+ define('--compile-concurrency CONCURRENCY', Integer,
187
+ 'Maximum number of simultaneous manifest block compiles (default: number of cores)') do |concurrency|
188
+ @options[:'compile-concurrency'] = concurrency
189
+ end
186
190
  define('--modulepath MODULES',
187
191
  "List of directories containing modules, separated by '#{File::PATH_SEPARATOR}'") do |modulepath|
188
192
  @options[:modulepath] = modulepath.split(File::PATH_SEPARATOR)
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bolt/pal'
4
+ require 'bolt/puppetdb'
5
+ require 'bolt/util/on_access'
4
6
 
5
7
  Bolt::PAL.load_puppet
6
8
 
@@ -53,13 +55,7 @@ end
53
55
 
54
56
  module Bolt
55
57
  class Catalog
56
- def in_env
57
- Puppet::Pal.in_tmp_environment('bolt_apply', modulepath: ['~/bolt/modules/'], facts: @scope['facts']) do |pal|
58
- yield pal
59
- end
60
- end
61
-
62
- def with_puppet_settings
58
+ def with_puppet_settings(hiera_config)
63
59
  Dir.mktmpdir('bolt') do |dir|
64
60
  cli = []
65
61
  Puppet::Settings::REQUIRED_APP_SETTINGS.each do |setting|
@@ -67,20 +63,19 @@ module Bolt
67
63
  end
68
64
  Puppet.settings.send(:clear_everything_for_tests)
69
65
  Puppet.initialize_settings(cli)
66
+ Puppet.settings[:hiera_config] = hiera_config
70
67
  # self.class.configure_logging
71
68
  yield
72
69
  end
73
70
  end
74
71
 
75
- def setup_node(node)
72
+ def setup_node(node, trusted)
76
73
  facts = Puppet.lookup(:pal_facts)
77
74
  node_facts = Puppet::Node::Facts.new(Puppet[:node_name_value], facts)
78
75
  node.fact_merge(node_facts)
79
76
 
80
77
  node.parameters = node.parameters.merge(Puppet.lookup(:pal_variables))
81
- # TODO: setup server_facts
82
- # TODO: setup trusted in params
83
- # TODO: setup serverversion/clientversion in params
78
+ node.trusted_data = trusted
84
79
  end
85
80
 
86
81
  def compile_node(node)
@@ -101,7 +96,13 @@ module Bolt
101
96
  def compile_catalog(request)
102
97
  pal_main = request['code_ast'] || request['code_string']
103
98
  target = request['target']
104
- with_puppet_settings do
99
+
100
+ pdb_client = Bolt::Util::OnAccess.new do
101
+ pdb_config = Bolt::PuppetDB::Config.new(nil, request['pdb_config'])
102
+ Bolt::PuppetDB::Client.from_config(pdb_config)
103
+ end
104
+
105
+ with_puppet_settings(request['hiera_config']) do
105
106
  Puppet[:code] = ''
106
107
  Puppet[:node_name_value] = target['name']
107
108
  Puppet::Pal.in_tmp_environment(
@@ -111,9 +112,9 @@ module Bolt
111
112
  variables: target["variables"] || {}
112
113
  ) do |_pal|
113
114
  node = Puppet.lookup(:pal_current_node)
114
- setup_node(node)
115
+ setup_node(node, target["trusted"])
115
116
 
116
- Puppet.override(pal_main: pal_main) do
117
+ Puppet.override(pal_main: pal_main, bolt_pdb_client: pdb_client) do
117
118
  compile_node(node)
118
119
  end
119
120
  end
@@ -262,7 +262,7 @@ module Bolt
262
262
  params: params }
263
263
  plan_context[:description] = options[:description] if options[:description]
264
264
 
265
- executor = Bolt::Executor.new(config, @analytics, options[:noop])
265
+ executor = Bolt::Executor.new(config, @analytics, options[:noop], bundled_content: bundled_content)
266
266
  executor.start_plan(plan_context)
267
267
  result = pal.run_plan(options[:object], options[:task_options], executor, inventory, puppetdb_client)
268
268
 
@@ -271,7 +271,7 @@ module Bolt
271
271
  outputter.print_plan_result(result)
272
272
  code = result.ok? ? 0 : 1
273
273
  else
274
- executor = Bolt::Executor.new(config, @analytics, options[:noop])
274
+ executor = Bolt::Executor.new(config, @analytics, options[:noop], bundled_content: bundled_content)
275
275
  targets = options[:targets]
276
276
 
277
277
  results = nil
@@ -353,5 +353,16 @@ module Bolt
353
353
  def outputter
354
354
  @outputter ||= Bolt::Outputter.for_format(config[:format], config[:color], config[:trace])
355
355
  end
356
+
357
+ def bundled_content
358
+ default_content = Bolt::PAL.new(Bolt::Config.new)
359
+ plans = default_content.list_plans.each_with_object([]) do |iter, col|
360
+ col << iter&.first
361
+ end
362
+ tasks = default_content.list_tasks.each_with_object([]) do |iter, col|
363
+ col << iter&.first
364
+ end
365
+ plans.concat tasks
366
+ end
356
367
  end
357
368
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'yaml'
4
4
  require 'logging'
5
+ require 'concurrent'
5
6
  require 'bolt/cli'
6
7
  require 'bolt/transport/ssh'
7
8
  require 'bolt/transport/winrm'
@@ -25,12 +26,14 @@ module Bolt
25
26
 
26
27
  Config = Struct.new(
27
28
  :concurrency,
29
+ :'compile-concurrency',
28
30
  :format,
29
31
  :trace,
30
32
  :inventoryfile,
31
33
  :log,
32
34
  :modulepath,
33
35
  :puppetdb,
36
+ :'hiera-config',
34
37
  :color,
35
38
  :transport,
36
39
  :transports
@@ -38,6 +41,7 @@ module Bolt
38
41
 
39
42
  DEFAULTS = {
40
43
  concurrency: 100,
44
+ 'compile-concurrency': Concurrent.processor_count,
41
45
  transport: 'ssh',
42
46
  format: 'human',
43
47
  modulepath: [],
@@ -131,7 +135,7 @@ module Bolt
131
135
  self[:modulepath] = data['modulepath'].split(File::PATH_SEPARATOR)
132
136
  end
133
137
 
134
- %w[inventoryfile concurrency format puppetdb color transport].each do |key|
138
+ %w[inventoryfile concurrency compile-concurrency format puppetdb hiera-config color transport].each do |key|
135
139
  if data.key?(key)
136
140
  self[key.to_sym] = data[key]
137
141
  end
@@ -197,8 +201,12 @@ module Bolt
197
201
  File.join(boltdir, 'inventory.yaml')
198
202
  end
199
203
 
204
+ def default_hiera
205
+ File.join(boltdir, 'hiera.yaml')
206
+ end
207
+
200
208
  def update_from_cli(options)
201
- %i[concurrency transport format trace modulepath inventoryfile color].each do |key|
209
+ %i[concurrency compile-concurrency transport format trace modulepath inventoryfile color].each do |key|
202
210
  self[key] = options[key] if options.key?(key)
203
211
  end
204
212
 
@@ -236,6 +244,7 @@ module Bolt
236
244
  # 'inventoryfile' cannot be included here or they will not be handled correctly.
237
245
  def update_from_defaults
238
246
  self[:modulepath] = default_modulepath
247
+ self[:'hiera-config'] = default_hiera
239
248
  end
240
249
 
241
250
  # The order in which config is processed is important
@@ -248,6 +257,7 @@ module Bolt
248
257
  def load_file(path)
249
258
  data = Bolt::Util.read_config_file(path, [default_config], 'config')
250
259
  update_from_file(data) if data
260
+ validate_hiera_conf(data ? data['hiera-config'] : nil)
251
261
  end
252
262
 
253
263
  def update_from_inventory(data)
@@ -263,6 +273,10 @@ module Bolt
263
273
  transports: self[:transports] }
264
274
  end
265
275
 
276
+ def validate_hiera_conf(path)
277
+ Bolt::Util.read_config_file(path, [default_hiera], 'hiera-config')
278
+ end
279
+
266
280
  def validate
267
281
  self[:log].each_pair do |name, params|
268
282
  if params.key?(:level) && !Bolt::Logger.valid_level?(params[:level])
@@ -274,6 +288,19 @@ module Bolt
274
288
  end
275
289
  end
276
290
 
291
+ unless self[:concurrency].is_a?(Integer) && self[:concurrency] > 0
292
+ raise Bolt::ValidationError, 'Concurrency must be a positive integer'
293
+ end
294
+
295
+ unless self[:'compile-concurrency'].is_a?(Integer) && self[:'compile-concurrency'] > 0
296
+ raise Bolt::ValidationError, 'Compile concurrency must be a positive integer'
297
+ end
298
+
299
+ compile_limit = 2 * Concurrent.processor_count
300
+ unless self[:'compile-concurrency'] < compile_limit
301
+ raise Bolt::ValidationError, "Compilation is CPU-intensive, set concurrency less than #{compile_limit}"
302
+ end
303
+
277
304
  unless %w[human json].include? self[:format]
278
305
  raise Bolt::ValidationError, "Unsupported format: '#{self[:format]}'"
279
306
  end
@@ -94,7 +94,7 @@ module Bolt
94
94
 
95
95
  class ValidationError < Bolt::Error
96
96
  def initialize(msg)
97
- super(msg, 'bolt.transport/validation-error')
97
+ super(msg, 'bolt/validation-error')
98
98
  end
99
99
  end
100
100
 
@@ -18,9 +18,13 @@ module Bolt
18
18
  attr_reader :noop, :transports
19
19
  attr_accessor :run_as, :plan_logging
20
20
 
21
- def initialize(config = Bolt::Config.new, analytics = Bolt::Analytics::NoopClient.new, noop = nil)
21
+ def initialize(config = Bolt::Config.new,
22
+ analytics = Bolt::Analytics::NoopClient.new,
23
+ noop = nil,
24
+ bundled_content: nil)
22
25
  @config = config
23
26
  @analytics = analytics
27
+ @bundled_content = bundled_content
24
28
  @logger = Logging.logger[self]
25
29
  @plan_logging = false
26
30
 
@@ -46,15 +50,14 @@ module Bolt
46
50
  impl.value
47
51
  end
48
52
 
49
- # Execute the given block on a list of nodes in parallel, one thread per "batch".
53
+ # Starts executing the given block on a list of nodes in parallel, one thread per "batch".
50
54
  #
51
55
  # This is the main driver of execution on a list of targets. It first
52
56
  # groups targets by transport, then divides each group into batches as
53
- # defined by the transport. Each batch, along with the corresponding
54
- # transport, is yielded to the block in turn and the results all collected
55
- # into a single ResultSet.
56
- def batch_execute(targets)
57
- promises = targets.group_by(&:protocol).flat_map do |protocol, protocol_targets|
57
+ # defined by the transport. Yields each batch, along with the corresponding
58
+ # transport, to the block in turn and returns an array of result promises.
59
+ def queue_execute(targets)
60
+ targets.group_by(&:protocol).flat_map do |protocol, protocol_targets|
58
61
  transport = transport(protocol)
59
62
  report_transport(transport, protocol_targets.count)
60
63
  transport.batches(protocol_targets).flat_map do |batch|
@@ -90,9 +93,25 @@ module Bolt
90
93
  batch_promises.values
91
94
  end
92
95
  end
96
+ end
97
+
98
+ # Create a ResultSet from the results of all promises.
99
+ def await_results(promises)
93
100
  ResultSet.new(promises.map(&:value))
94
101
  end
95
102
 
103
+ # Execute the given block on a list of nodes in parallel, one thread per "batch".
104
+ #
105
+ # This is the main driver of execution on a list of targets. It first
106
+ # groups targets by transport, then divides each group into batches as
107
+ # defined by the transport. Each batch, along with the corresponding
108
+ # transport, is yielded to the block in turn and the results all collected
109
+ # into a single ResultSet.
110
+ def batch_execute(targets, &block)
111
+ promises = queue_execute(targets, &block)
112
+ await_results(promises)
113
+ end
114
+
96
115
  def log_action(description, targets)
97
116
  # When running a plan, info messages like starting a task are promoted to notice.
98
117
  log_method = @plan_logging ? :notice : :info
@@ -115,7 +134,6 @@ module Bolt
115
134
 
116
135
  results
117
136
  end
118
- private :log_action
119
137
 
120
138
  def report_transport(transport, count)
121
139
  name = transport.class.name.split('::').last.downcase
@@ -127,13 +145,18 @@ module Bolt
127
145
  @analytics&.event('Plan', 'call_function', function)
128
146
  end
129
147
 
148
+ def report_bundled_content(mode, name)
149
+ if @bundled_content&.include?(name)
150
+ @analytics&.event('Bundled Content', mode, name)
151
+ end
152
+ end
153
+
130
154
  def with_node_logging(description, batch)
131
155
  @logger.info("#{description} on #{batch.map(&:uri)}")
132
156
  result = yield
133
157
  @logger.info(result.to_json)
134
158
  result
135
159
  end
136
- private :with_node_logging
137
160
 
138
161
  def run_command(targets, command, options = {}, &callback)
139
162
  description = options.fetch('_description', "command '#{command}'")
@@ -119,7 +119,14 @@ module Bolt
119
119
  bolt_executor: executor,
120
120
  bolt_inventory: inventory,
121
121
  bolt_pdb_client: pdb_client,
122
- apply_executor: Applicator.new(inventory, executor)
122
+ apply_executor: Applicator.new(
123
+ inventory,
124
+ executor,
125
+ full_modulepath(@config[:modulepath]),
126
+ @config.puppetdb,
127
+ @config[:'hiera-config'],
128
+ @config[:'compile-concurrency']
129
+ )
123
130
  }
124
131
  Puppet.override(opts, &block)
125
132
  end
@@ -132,6 +132,7 @@ module Bolt
132
132
 
133
133
  if ENVIRONMENT_METHODS.include?(input_method)
134
134
  environment = arguments.inject({}) do |env, (param, val)|
135
+ val = val.to_json unless val.is_a?(String)
135
136
  env.merge("PT_#{param}" => val)
136
137
  end
137
138
  execute_options[:environment] = environment
@@ -112,6 +112,7 @@ catch
112
112
 
113
113
  if ENVIRONMENT_METHODS.include?(input_method)
114
114
  arguments.each do |(arg, val)|
115
+ val = val.to_json unless val.is_a?(String)
115
116
  cmd = "[Environment]::SetEnvironmentVariable('PT_#{arg}', @'\n#{val}\n'@)"
116
117
  result = conn.execute(cmd)
117
118
  if result.exit_code != 0
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bolt
4
- VERSION = '0.21.2'
4
+ VERSION = '0.21.3'
5
5
  end
@@ -7,12 +7,15 @@ require 'json'
7
7
 
8
8
  # This accepts a catalog request on stdin:
9
9
  # { "code_ast": "JSON serialized Puppet AST",
10
- # "code_string": "String of code, ignored if AST is provided,
11
- # "modulepath": "Array of directories to use as the modulepath for catalog compilation.
10
+ # "code_string": "String of code, ignored if AST is provided",
11
+ # "modulepath": "Array of directories to use as the modulepath for catalog compilation",
12
+ # "pdb_config": "A hash of PDB client config options as supplied to Bolt",
13
+ # "hiera_config": "File path to hiera config file",
12
14
  # "target": {
13
- # "name": "the name of the node usually fqdn fro url",
14
- # "facts": "Hash of facts to use for the node",
15
- # "variables": "Hash of variables to use for compilation"
15
+ # "name": "the name of the node usually fqdn fro url",
16
+ # "facts": "Hash of facts to use for the node",
17
+ # "variables": "Hash of variables to use for compilation",
18
+ # "trusted": "Hash of trusted data for the node"
16
19
  # }
17
20
  # }
18
21
 
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: 0.21.2
4
+ version: 0.21.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-07-09 00:00:00.000000000 Z
11
+ date: 2018-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.2.4
89
+ version: '0.2'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.2.4
96
+ version: '0.2'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: terminal-table
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -198,14 +198,14 @@ dependencies:
198
198
  requirements:
199
199
  - - "~>"
200
200
  - !ruby/object:Gem::Version
201
- version: 1.0.2
201
+ version: '1.0'
202
202
  type: :runtime
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
206
  - - "~>"
207
207
  - !ruby/object:Gem::Version
208
- version: 1.0.2
208
+ version: '1.0'
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: bundler
211
211
  requirement: !ruby/object:Gem::Requirement