bolt 1.26.0 → 1.27.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2431380225c5f60abf51caa85cfa1ee3aeadcf1ef494192e93bfb8f7e175d7f9
4
- data.tar.gz: a49aa9489c0992bcaab219b54fe054dd3ef8d078231cf64ed7e039c8c580bb46
3
+ metadata.gz: ab9cf181769b6ca24ef2b29fc8179d3bf53dec09d017c4e611a2d164d4674dfb
4
+ data.tar.gz: ff29ec62872a9f46f9ab36a50369255ad0ab2de350bf7867719e4663ba623978
5
5
  SHA512:
6
- metadata.gz: 2a28ce31a001a91307ce8e31cf4307a7eac3f5027143444eae22a49e406820e808bdffa668a9daad5b52bec76413af55a28c50b2aa439d4516951370d7f15210
7
- data.tar.gz: fa64ecb34705bb81e728ce9067928bcde35b51630d672d8666d09766f941c26811466608f03927852061a5848135b7ee2d6725224770f0a743404a6e8840422f
6
+ metadata.gz: 4013b9347614f3c6959ed0c69ad9a6d3ed61e8cc557198b12e23bdaadc44b297724872b71fe55cdb9e43b37d7c7ccad9df7935ae52f926d2f83c7776d02a4949
7
+ data.tar.gz: 6190e0d6bc138a4a9da01d37d2771d089587da9279f14673bb22d45b3f87f27e621e281dfb2a0f8e67a38bb2d70342928952c500875febb76f7b8800750fd434
@@ -2,7 +2,8 @@
2
2
 
3
3
  # Output a message for the user.
4
4
  #
5
- # This will print a message to stdout when using the human output format.
5
+ # This will print a message to stdout when using the human output format,
6
+ # and print to stderr when using the json output format
6
7
  #
7
8
  # **NOTE:** Not available in apply block
8
9
  Puppet::Functions.create_function(:'out::message') do
@@ -21,7 +21,9 @@ module Bolt
21
21
  statement_count: :cd6,
22
22
  resource_mean: :cd7,
23
23
  plan_steps: :cd8,
24
- return_type: :cd9
24
+ return_type: :cd9,
25
+ inventory_version: :cd10,
26
+ boltdir_type: :cd11
25
27
  }.freeze
26
28
 
27
29
  def self.build_client
@@ -74,7 +76,7 @@ module Bolt
74
76
  @user_id = user_id
75
77
  @executor = Concurrent.global_io_executor
76
78
  @os = compute_os
77
- @bundled_content = []
79
+ @bundled_content = {}
78
80
  end
79
81
 
80
82
  def screen_view(screen, **kwargs)
@@ -92,6 +94,12 @@ module Bolt
92
94
  submit(base_params.merge(screen_view_params))
93
95
  end
94
96
 
97
+ def report_bundled_content(mode, name)
98
+ if bundled_content[mode.split.first]&.include?(name)
99
+ event('Bundled Content', mode, label: name)
100
+ end
101
+ end
102
+
95
103
  def event(category, action, label: nil, value: nil, **kwargs)
96
104
  custom_dimensions = Bolt::Util.walk_keys(kwargs) do |k|
97
105
  CUSTOM_DIMENSIONS[k] || raise("Unknown analytics key '#{k}'")
@@ -177,6 +185,8 @@ module Bolt
177
185
  @logger.debug "Skipping submission of '#{screen}' screenview because analytics is disabled"
178
186
  end
179
187
 
188
+ def report_bundled_content(mode, name); end
189
+
180
190
  def event(category, action, **_kwargs)
181
191
  @logger.debug "Skipping submission of '#{category} #{action}' event because analytics is disabled"
182
192
  end
@@ -6,10 +6,10 @@ module Bolt
6
6
  class Boltdir
7
7
  BOLTDIR_NAME = 'Boltdir'
8
8
 
9
- attr_reader :path, :config_file, :inventory_file, :modulepath, :hiera_config, :puppetfile, :rerunfile
9
+ attr_reader :path, :config_file, :inventory_file, :modulepath, :hiera_config, :puppetfile, :rerunfile, :type
10
10
 
11
11
  def self.default_boltdir
12
- Boltdir.new(File.join('~', '.puppetlabs', 'bolt'))
12
+ Boltdir.new(File.join('~', '.puppetlabs', 'bolt'), 'user')
13
13
  end
14
14
 
15
15
  # Search recursively up the directory hierarchy for the Boltdir. Look for a
@@ -19,9 +19,9 @@ module Bolt
19
19
  def self.find_boltdir(dir)
20
20
  dir = Pathname.new(dir)
21
21
  if (dir + BOLTDIR_NAME).directory?
22
- new(dir + BOLTDIR_NAME)
22
+ new(dir + BOLTDIR_NAME, 'embedded')
23
23
  elsif (dir + 'bolt.yaml').file?
24
- new(dir)
24
+ new(dir, 'local')
25
25
  elsif dir.root?
26
26
  default_boltdir
27
27
  else
@@ -29,7 +29,7 @@ module Bolt
29
29
  end
30
30
  end
31
31
 
32
- def initialize(path)
32
+ def initialize(path, type = 'option')
33
33
  @path = Pathname.new(path).expand_path
34
34
  @config_file = @path + 'bolt.yaml'
35
35
  @inventory_file = @path + 'inventory.yaml'
@@ -37,6 +37,7 @@ module Bolt
37
37
  @hiera_config = @path + 'hiera.yaml'
38
38
  @puppetfile = @path + 'Puppetfile'
39
39
  @rerunfile = @path + '.rerun.json'
40
+ @type = type
40
41
  end
41
42
 
42
43
  def to_s
@@ -242,7 +242,7 @@ module Bolt
242
242
  end
243
243
 
244
244
  def plugins
245
- @plugins ||= Bolt::Plugin.setup(config, puppetdb_client)
245
+ @plugins ||= Bolt::Plugin.setup(config, puppetdb_client, analytics)
246
246
  end
247
247
 
248
248
  def query_puppetdb_nodes(query)
@@ -264,9 +264,6 @@ module Bolt
264
264
  return 0
265
265
  end
266
266
 
267
- @analytics = Bolt::Analytics.build_client
268
- @analytics.bundled_content = bundled_content
269
-
270
267
  screen = "#{options[:subcommand]}_#{options[:action]}"
271
268
  # submit a different screen for `bolt task show` and `bolt task show foo`
272
269
  if options[:action] == 'show' && options[:object]
@@ -274,7 +271,8 @@ module Bolt
274
271
  end
275
272
 
276
273
  screen_view_fields = {
277
- output_format: config.format
274
+ output_format: config.format,
275
+ boltdir_type: config.boltdir.type
278
276
  }
279
277
 
280
278
  # Only include target and inventory info for commands that take a targets
@@ -282,10 +280,11 @@ module Bolt
282
280
  if options.key?(:targets)
283
281
  screen_view_fields.merge!(target_nodes: options[:targets].count,
284
282
  inventory_nodes: inventory.node_names.count,
285
- inventory_groups: inventory.group_names.count)
283
+ inventory_groups: inventory.group_names.count,
284
+ inventory_version: inventory.version)
286
285
  end
287
286
 
288
- @analytics.screen_view(screen, screen_view_fields)
287
+ analytics.screen_view(screen, screen_view_fields)
289
288
 
290
289
  if options[:action] == 'show'
291
290
  if options[:subcommand] == 'task'
@@ -329,7 +328,7 @@ module Bolt
329
328
  end
330
329
  code = apply_manifest(options[:code], options[:targets], options[:object], options[:noop])
331
330
  else
332
- executor = Bolt::Executor.new(config.concurrency, @analytics, options[:noop])
331
+ executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop])
333
332
  targets = options[:targets]
334
333
 
335
334
  results = nil
@@ -380,7 +379,7 @@ module Bolt
380
379
  ensure
381
380
  # restore original signal handler
382
381
  Signal.trap :INT, handler if handler
383
- @analytics&.finish
382
+ analytics&.finish
384
383
  end
385
384
 
386
385
  def show_task(task_name)
@@ -420,8 +419,14 @@ module Bolt
420
419
  params: params }
421
420
  plan_context[:description] = options[:description] if options[:description]
422
421
 
423
- executor = Bolt::Executor.new(config.concurrency, @analytics, options[:noop])
424
- executor.subscribe(outputter) if options.fetch(:format, 'human') == 'human'
422
+ executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop])
423
+ if options.fetch(:format, 'human') == 'human'
424
+ executor.subscribe(outputter)
425
+ else
426
+ # Only subscribe to out::message events for JSON outputter
427
+ executor.subscribe(outputter, [:message])
428
+ end
429
+
425
430
  executor.subscribe(log_outputter)
426
431
  executor.start_plan(plan_context)
427
432
  result = pal.run_plan(plan_name, plan_arguments, executor, inventory, puppetdb_client)
@@ -438,7 +443,7 @@ module Bolt
438
443
  def apply_manifest(code, targets, filename = nil, noop = false)
439
444
  ast = pal.parse_manifest(code, filename)
440
445
 
441
- executor = Bolt::Executor.new(config.concurrency, @analytics, noop)
446
+ executor = Bolt::Executor.new(config.concurrency, analytics, noop)
442
447
  executor.subscribe(outputter) if options.fetch(:format, 'human') == 'human'
443
448
  executor.subscribe(log_outputter)
444
449
  # apply logging looks like plan logging, so tell the outputter we're in a
@@ -525,20 +530,30 @@ module Bolt
525
530
  @log_outputter ||= Bolt::Outputter::Logger.new(options[:verbose], config.trace)
526
531
  end
527
532
 
533
+ def analytics
534
+ @analytics ||= begin
535
+ client = Bolt::Analytics.build_client
536
+ client.bundled_content = bundled_content
537
+ client
538
+ end
539
+ end
540
+
528
541
  def bundled_content
529
542
  # We only need to enumerate bundled content when running a task or plan
543
+ content = { 'Plan' => [],
544
+ 'Task' => [],
545
+ 'Plugin' => %w[puppetdb pkcs7 prompt terraform task] }
530
546
  if %w[plan task].include?(options[:subcommand]) && options[:action] == 'run'
531
547
  default_content = Bolt::PAL.new([], nil)
532
- plans = default_content.list_plans.each_with_object([]) do |iter, col|
548
+ content['Plan'] = default_content.list_plans.each_with_object([]) do |iter, col|
533
549
  col << iter&.first
534
550
  end
535
- tasks = default_content.list_tasks.each_with_object([]) do |iter, col|
551
+ content['Task'] = default_content.list_tasks.each_with_object([]) do |iter, col|
536
552
  col << iter&.first
537
553
  end
538
- plans.concat tasks
539
- else
540
- []
541
554
  end
555
+
556
+ content
542
557
  end
543
558
  end
544
559
  end
@@ -31,14 +31,14 @@ module Bolt
31
31
  end
32
32
 
33
33
  class Config
34
- attr_accessor :concurrency, :format, :trace, :log, :puppetdb, :color, :save_rerun,
34
+ attr_accessor :aws, :concurrency, :format, :trace, :log, :puppetdb, :color, :save_rerun,
35
35
  :transport, :transports, :inventoryfile, :compile_concurrency, :boltdir,
36
36
  :puppetfile_config, :plugins
37
37
  attr_writer :modulepath
38
38
 
39
39
  TRANSPORT_OPTIONS = %i[password run-as sudo-password extensions
40
40
  private-key tty tmpdir user connect-timeout
41
- cacert token-file service-url interpreters file-protocol smb-port].freeze
41
+ cacert token-file service-url interpreters file-protocol smb-port realm].freeze
42
42
 
43
43
  PUPPETFILE_OPTIONS = %w[proxy forge].freeze
44
44
 
@@ -162,7 +162,7 @@ module Bolt
162
162
  # Plugins are only settable from config not inventory so we can overwrite
163
163
  @plugins = data['plugins'] if data.key?('plugins')
164
164
 
165
- %w[concurrency format puppetdb color transport].each do |key|
165
+ %w[aws concurrency format puppetdb color transport].each do |key|
166
166
  send("#{key}=", data[key]) if data.key?(key)
167
167
  end
168
168
 
@@ -40,7 +40,7 @@ module Bolt
40
40
  end
41
41
  end
42
42
  @reported_transports = Set.new
43
- @subscribers = Set.new
43
+ @subscribers = {}
44
44
  @publisher = Concurrent::SingleThreadExecutor.new
45
45
 
46
46
  @noop = noop
@@ -61,13 +61,16 @@ module Bolt
61
61
  impl.value
62
62
  end
63
63
 
64
- def subscribe(subscriber)
65
- @subscribers << subscriber
64
+ def subscribe(subscriber, types = nil)
65
+ @subscribers[subscriber] = types
66
66
  self
67
67
  end
68
68
 
69
69
  def publish_event(event)
70
- @subscribers.each do |subscriber|
70
+ @subscribers.each do |subscriber, types|
71
+ # If types isn't set or if the subscriber is subscribed to
72
+ # that type of event, publish the event
73
+ next unless types.nil? || types.include?(event[:type])
71
74
  @publisher.post(subscriber) do |sub|
72
75
  sub.handle_event(event)
73
76
  end
@@ -186,9 +189,7 @@ module Bolt
186
189
  end
187
190
 
188
191
  def report_bundled_content(mode, name)
189
- if @analytics.bundled_content&.include?(name)
190
- @analytics&.event('Bundled Content', mode, label: name)
191
- end
192
+ @analytics.report_bundled_content(mode, name)
192
193
  end
193
194
 
194
195
  def report_apply(statement_count, resource_counts)
@@ -245,7 +246,7 @@ module Bolt
245
246
  options = { '_run_as' => run_as }.merge(options) if run_as
246
247
 
247
248
  batch_execute(targets) do |transport, batch|
248
- with_node_logging("Running script #{script} with '#{arguments}'", batch) do
249
+ with_node_logging("Running script #{script} with '#{arguments.to_json}'", batch) do
249
250
  transport.batch_script(batch, script, arguments, options, &method(:publish_event))
250
251
  end
251
252
  end
@@ -259,7 +260,7 @@ module Bolt
259
260
  arguments['_task'] = task.name
260
261
 
261
262
  batch_execute(targets) do |transport, batch|
262
- with_node_logging("Running task #{task.name} with '#{arguments}'", batch) do
263
+ with_node_logging("Running task #{task.name} with '#{arguments.to_json}'", batch) do
263
264
  transport.batch_task(batch, task, arguments, options, &method(:publish_event))
264
265
  end
265
266
  end
@@ -90,6 +90,10 @@ module Bolt
90
90
  @groups.validate
91
91
  end
92
92
 
93
+ def version
94
+ 1
95
+ end
96
+
93
97
  def collect_groups
94
98
  # Provide a lookup map for finding a group by name
95
99
  @group_lookup = @groups.collect_groups
@@ -98,18 +98,27 @@ module Bolt
98
98
  def config_only_plugin(data)
99
99
  Bolt::Util.walk_vals(data) do |value|
100
100
  if value.is_a?(Hash) && value.include?('_plugin')
101
- unless (plugin = @plugins.by_name(value['_plugin']))
102
- raise ValidationError.new("Config lookup specifies an unknown plugin: #{value['_plugin'].inspect}", @name)
101
+ plugin_name = value['_plugin']
102
+ begin
103
+ hook = @plugins.get_hook(plugin_name, :inventory_config)
104
+ rescue Bolt::Plugin::PluginError => e
105
+ raise ValidationError.new(e.message, @name)
103
106
  end
104
- unless plugin.hooks.include?('inventory_config')
105
- raise ValidationError.new("#{plugin.name} does not support inventory_config.", @name)
107
+
108
+ begin
109
+ validate_proc = @plugins.get_hook(plugin_name, :validate_inventory_config)
110
+ rescue Bolt::Plugin::PluginError
111
+ validate_proc = proc { |*args| }
106
112
  end
107
- plugin.validate_inventory_config(value) if plugin.respond_to?(:validate_inventory_config)
113
+
114
+ validate_proc.call(value)
115
+
108
116
  Concurrent::Delay.new do
109
117
  begin
110
- plugin.inventory_config(value)
118
+ hook.call(value)
111
119
  rescue StandardError => e
112
- raise Bolt::Plugin::PluginError.new(e.message, plugin, "inventory_targets in #{@name}")
120
+ loc = "inventory_config in #{@name}"
121
+ raise Bolt::Plugin::PluginError::ExecutionError.new(e.message, plugin_name, loc)
113
122
  end
114
123
  end
115
124
  else
@@ -200,17 +209,17 @@ module Bolt
200
209
  end
201
210
 
202
211
  def lookup_targets(lookup)
203
- unless (plugin = @plugins.by_name(lookup['_plugin']))
204
- raise ValidationError.new("Target lookup specifies an unknown plugin: '#{lookup['plugin']}'", @name)
205
- end
206
- unless plugin.hooks.include?('inventory_targets')
207
- raise ValidationError.new("#{plugin.name} does not support inventory_targets.", @name)
212
+ begin
213
+ hook = @plugins.get_hook(lookup['_plugin'], :inventory_targets)
214
+ rescue Bolt::Plugin::PluginError => e
215
+ raise ValidationError.new(e.message, @name)
208
216
  end
209
217
 
210
218
  begin
211
- targets = plugin.inventory_targets(lookup)
219
+ targets = hook.call(lookup)
212
220
  rescue StandardError => e
213
- raise Bolt::Plugin::PluginError.new(e.message, plugin, "inventory_targets in #{@name}")
221
+ loc = "inventory_targets in #{@name}"
222
+ raise Bolt::Plugin::PluginError::ExecutionError.new(e.message, lookup['_plugin'], loc)
214
223
  end
215
224
 
216
225
  targets.each { |target| add_target(target) }
@@ -30,6 +30,10 @@ module Bolt
30
30
  @groups.validate
31
31
  end
32
32
 
33
+ def version
34
+ 2
35
+ end
36
+
33
37
  def collect_groups
34
38
  # Provide a lookup map for finding a group by name
35
39
  @group_lookup = @groups.collect_groups
@@ -21,6 +21,8 @@ module Bolt
21
21
  case event[:type]
22
22
  when :node_result
23
23
  print_result(event[:result])
24
+ when :message
25
+ print_message_event(event)
24
26
  end
25
27
  end
26
28
 
@@ -106,7 +108,13 @@ module Bolt
106
108
  @stream.puts '}' if @object_open
107
109
  end
108
110
 
109
- def print_message(message); end
111
+ def print_message_event(event)
112
+ print_message(event[:message])
113
+ end
114
+
115
+ def print_message(message)
116
+ $stderr.puts(message)
117
+ end
110
118
  end
111
119
  end
112
120
  end
@@ -5,27 +5,45 @@ require 'bolt/plugin/terraform'
5
5
  require 'bolt/plugin/pkcs7'
6
6
  require 'bolt/plugin/prompt'
7
7
  require 'bolt/plugin/task'
8
+ require 'bolt/plugin/aws'
8
9
 
9
10
  module Bolt
10
11
  class Plugin
11
12
  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')
13
+ class ExecutionError < PluginError
14
+ def initialize(msg, plugin_name, location)
15
+ mess = "Error executing plugin: #{plugin_name} from #{location}: #{msg}"
16
+ super(mess, 'bolt/plugin-error')
17
+ end
18
+ end
19
+
20
+ class Unknown < PluginError
21
+ def initialize(plugin_name)
22
+ super("Unknown plugin: '#{plugin_name}'", 'bolt/unknown-plugin')
23
+ end
24
+ end
25
+
26
+ class UnsupportedHook < PluginError
27
+ def initialize(plugin_name, hook)
28
+ super("Plugin #{plugin_name} does not support #{hook}", 'bolt/unsupported-hook')
29
+ end
15
30
  end
16
31
  end
17
32
 
18
- def self.setup(config, pdb_client)
19
- plugins = new(config)
33
+ def self.setup(config, pdb_client, analytics)
34
+ plugins = new(config, analytics)
20
35
  plugins.add_plugin(Bolt::Plugin::Puppetdb.new(pdb_client))
21
36
  plugins.add_plugin(Bolt::Plugin::Terraform.new)
22
37
  plugins.add_plugin(Bolt::Plugin::Prompt.new)
23
38
  plugins.add_plugin(Bolt::Plugin::Pkcs7.new(config.boltdir.path, config.plugins['pkcs7'] || {}))
24
39
  plugins.add_plugin(Bolt::Plugin::Task.new(config))
40
+ plugins.add_plugin(Bolt::Plugin::Aws::EC2.new(config))
25
41
  plugins
26
42
  end
27
43
 
28
- def initialize(_config)
44
+ def initialize(config, analytics)
45
+ @config = config
46
+ @analytics = analytics
29
47
  @plugins = {}
30
48
  end
31
49
 
@@ -33,8 +51,13 @@ module Bolt
33
51
  @plugins[plugin.name] = plugin
34
52
  end
35
53
 
36
- def for_hook(hook)
37
- @plugins.filter { |_n, plug| plug.hooks.include? hook }
54
+ def get_hook(plugin_name, hook)
55
+ plugin = by_name(plugin_name)
56
+ raise PluginError::Unknown, plugin_name unless plugin
57
+ raise PluginError::UnsupportedHook.new(plugin_name, hook) unless plugin.respond_to?(hook)
58
+ @analytics.report_bundled_content("Plugin #{hook}", plugin_name)
59
+
60
+ plugin.method(hook)
38
61
  end
39
62
 
40
63
  def by_name(plugin_name)
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Bolt
6
+ class Plugin
7
+ class Aws
8
+ class EC2
9
+ attr_accessor :client
10
+ attr_reader :config
11
+
12
+ def initialize(config)
13
+ require 'aws-sdk-ec2'
14
+ @config = config
15
+ @logger = Logging.logger[self]
16
+ end
17
+
18
+ def name
19
+ 'aws::ec2'
20
+ end
21
+
22
+ def hooks
23
+ %w[inventory_targets]
24
+ end
25
+
26
+ def config_client(opts)
27
+ return client if client
28
+
29
+ options = {}
30
+
31
+ if opts.key?('region')
32
+ options[:region] = opts['region']
33
+ end
34
+ if opts.key?('profile')
35
+ options[:profile] = opts['profile']
36
+ end
37
+ if config.aws&.key?('credentials')
38
+ creds = File.expand_path(config.aws['credentials'])
39
+ if File.exist?(creds)
40
+ options[:credentials] = ::Aws::SharedCredentials.new(path: creds)
41
+ else
42
+ raise Bolt::ValidationError, "Cannot load credentials file #{config.aws['credentials']}"
43
+ end
44
+ end
45
+
46
+ ::Aws::EC2::Client.new(options)
47
+ end
48
+
49
+ def inventory_targets(opts)
50
+ client = config_client(opts)
51
+ resource = ::Aws::EC2::Resource.new(client: client)
52
+
53
+ # Retrieve a list of EC2 instances and create a list of targets
54
+ # Note: It doesn't seem possible to filter stubbed responses...
55
+ resource.instances(filters: opts['filters']).map do |instance|
56
+ next unless instance.state.name == 'running'
57
+ target = {}
58
+
59
+ if opts.key?('uri')
60
+ uri = lookup(instance, opts['uri'])
61
+ target['uri'] = uri if uri
62
+ end
63
+ if opts.key?('name')
64
+ real_name = lookup(instance, opts['name'])
65
+ target['name'] = real_name if real_name
66
+ end
67
+ if opts.key?('config')
68
+ target['config'] = resolve_config(instance, opts['config'])
69
+ end
70
+
71
+ target if target['uri'] || target['name']
72
+ end.compact
73
+ end
74
+
75
+ # Look for an instance attribute specified in the inventory file
76
+ def lookup(instance, attribute)
77
+ value = instance.data.respond_to?(attribute) ? instance.data[attribute] : nil
78
+ unless value
79
+ warn_missing_attribute(instance, attribute)
80
+ end
81
+ value
82
+ end
83
+
84
+ def warn_missing_attribute(instance, attribute)
85
+ @logger.warn("Could not find attribute #{attribute} of instance #{instance.instance_id}")
86
+ end
87
+
88
+ # Walk the "template" config mapping provided in the plugin config and
89
+ # replace all values with the corresponding value from the resource
90
+ # parameters.
91
+ def resolve_config(name, config_template)
92
+ Bolt::Util.walk_vals(config_template) do |value|
93
+ if value.is_a?(String)
94
+ lookup(name, value)
95
+ else
96
+ value
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -3,14 +3,15 @@
3
3
  module Bolt
4
4
  class Secret
5
5
  def self.execute(plugins, outputter, options)
6
- enc = plugins.by_name('pkcs7')
7
6
  case options[:action]
8
7
  when 'createkeys'
9
- enc.secret_createkeys
8
+ plugins.get_hook('pkcs7', :secret_createkeys).call
10
9
  when 'encrypt'
11
- outputter.print_message(enc.secret_encrypt('plaintext-value' => options[:object]))
10
+ encrypted = plugins.get_hook('pkcs7', :secret_encrypt).call('plaintext-value' => options[:object])
11
+ outputter.print_message(encrypted)
12
12
  when 'decrypt'
13
- outputter.print_message(enc.secret_decrypt('encrypted-value' => options[:object]))
13
+ decrypted = plugins.get_hook('pkcs7', :secret_decrypt).call('encrypted-value' => options[:object])
14
+ outputter.print_message(decrypted)
14
15
  end
15
16
 
16
17
  0
@@ -101,7 +101,7 @@ module Bolt
101
101
  def run_script(target, script, arguments, options = {})
102
102
  self.class.validate(options)
103
103
  with_tmpscript(File.absolute_path(script), target.options['tmpdir']) do |file, dir|
104
- logger.debug "Running '#{file}' with #{arguments}"
104
+ logger.debug "Running '#{file}' with #{arguments.to_json}"
105
105
 
106
106
  # unpack any Sensitive data AFTER we log
107
107
  arguments = unwrap_sensitive_args(arguments)
@@ -152,7 +152,7 @@ module Bolt
152
152
  interpreter = select_interpreter(script, target.options['interpreters'])
153
153
  interpreter_debug = interpreter ? " using '#{interpreter}' interpreter" : nil
154
154
  # log the arguments with sensitive data redacted, do NOT log unwrapped_arguments
155
- logger.debug("Running '#{script}' with #{arguments}#{interpreter_debug}")
155
+ logger.debug("Running '#{script}' with #{arguments.to_json}#{interpreter_debug}")
156
156
  unwrapped_arguments = unwrap_sensitive_args(arguments)
157
157
 
158
158
  stdin = STDIN_METHODS.include?(input_method) ? JSON.dump(unwrapped_arguments) : nil
@@ -91,7 +91,7 @@ module Bolt
91
91
  " using '#{execute_options[:interpreter]}' interpreter"
92
92
  end
93
93
  # log the arguments with sensitive data redacted, do NOT log unwrapped_arguments
94
- logger.debug("Running '#{executable}' with #{arguments}#{interpreter_debug}")
94
+ logger.debug("Running '#{executable}' with #{arguments.to_json}#{interpreter_debug}")
95
95
  # unpack any Sensitive data
96
96
  arguments = unwrap_sensitive_args(arguments)
97
97
 
@@ -10,7 +10,7 @@ module Bolt
10
10
  def self.options
11
11
  %w[
12
12
  host port user password connect-timeout ssl ssl-verify tmpdir
13
- cacert extensions interpreters file-protocol smb-port
13
+ cacert extensions interpreters file-protocol smb-port realm
14
14
  ]
15
15
  end
16
16
 
@@ -38,13 +38,17 @@ module Bolt
38
38
  scheme = 'http'
39
39
  transport = :negotiate
40
40
  end
41
+
42
+ transport = :kerberos if target.options['realm']
41
43
  endpoint = "#{scheme}://#{target.host}:#{@port}/wsman"
42
44
  options = { endpoint: endpoint,
43
- user: @user,
44
- password: target.password,
45
+ # https://github.com/WinRb/WinRM/issues/270
46
+ user: target.options['realm'] ? 'dummy' : @user,
47
+ password: target.options['realm'] ? 'dummy' : target.password,
45
48
  retry_limit: 1,
46
49
  transport: transport,
47
50
  ca_trust_path: target.options['cacert'],
51
+ realm: target.options['realm'],
48
52
  no_ssl_peer_verification: !target.options['ssl-verify'] }
49
53
 
50
54
  Timeout.timeout(target.options['connect-timeout']) do
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bolt
4
- VERSION = '1.26.0'
4
+ VERSION = '1.27.0'
5
5
  end
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.26.0
4
+ version: 1.27.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-07-09 00:00:00.000000000 Z
11
+ date: 2019-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk-ec2
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: CFPropertyList
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -396,6 +410,7 @@ files:
396
410
  - lib/bolt/pal/yaml_plan/transpiler.rb
397
411
  - lib/bolt/plan_result.rb
398
412
  - lib/bolt/plugin.rb
413
+ - lib/bolt/plugin/aws.rb
399
414
  - lib/bolt/plugin/pkcs7.rb
400
415
  - lib/bolt/plugin/prompt.rb
401
416
  - lib/bolt/plugin/puppetdb.rb