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 +4 -4
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +2 -1
- data/lib/bolt/analytics.rb +12 -2
- data/lib/bolt/boltdir.rb +6 -5
- data/lib/bolt/cli.rb +32 -17
- data/lib/bolt/config.rb +3 -3
- data/lib/bolt/executor.rb +10 -9
- data/lib/bolt/inventory.rb +4 -0
- data/lib/bolt/inventory/group2.rb +23 -14
- data/lib/bolt/inventory/inventory2.rb +4 -0
- data/lib/bolt/outputter/json.rb +9 -1
- data/lib/bolt/plugin.rb +31 -8
- data/lib/bolt/plugin/aws.rb +103 -0
- data/lib/bolt/secret.rb +5 -4
- data/lib/bolt/transport/local_windows.rb +2 -2
- data/lib/bolt/transport/sudoable.rb +1 -1
- data/lib/bolt/transport/winrm.rb +1 -1
- data/lib/bolt/transport/winrm/connection.rb +6 -2
- data/lib/bolt/version.rb +1 -1
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab9cf181769b6ca24ef2b29fc8179d3bf53dec09d017c4e611a2d164d4674dfb
|
4
|
+
data.tar.gz: ff29ec62872a9f46f9ab36a50369255ad0ab2de350bf7867719e4663ba623978
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/bolt/analytics.rb
CHANGED
@@ -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
|
data/lib/bolt/boltdir.rb
CHANGED
@@ -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
|
data/lib/bolt/cli.rb
CHANGED
@@ -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
|
-
|
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,
|
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
|
-
|
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,
|
424
|
-
|
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,
|
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
|
-
|
548
|
+
content['Plan'] = default_content.list_plans.each_with_object([]) do |iter, col|
|
533
549
|
col << iter&.first
|
534
550
|
end
|
535
|
-
|
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
|
data/lib/bolt/config.rb
CHANGED
@@ -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
|
|
data/lib/bolt/executor.rb
CHANGED
@@ -40,7 +40,7 @@ module Bolt
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
@reported_transports = Set.new
|
43
|
-
@subscribers =
|
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
|
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
|
-
|
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
|
data/lib/bolt/inventory.rb
CHANGED
@@ -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
|
-
|
102
|
-
|
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
|
-
|
105
|
-
|
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
|
-
|
113
|
+
|
114
|
+
validate_proc.call(value)
|
115
|
+
|
108
116
|
Concurrent::Delay.new do
|
109
117
|
begin
|
110
|
-
|
118
|
+
hook.call(value)
|
111
119
|
rescue StandardError => e
|
112
|
-
|
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
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
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 =
|
219
|
+
targets = hook.call(lookup)
|
212
220
|
rescue StandardError => e
|
213
|
-
|
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) }
|
data/lib/bolt/outputter/json.rb
CHANGED
@@ -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
|
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
|
data/lib/bolt/plugin.rb
CHANGED
@@ -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
|
-
|
13
|
-
|
14
|
-
|
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(
|
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
|
37
|
-
|
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
|
data/lib/bolt/secret.rb
CHANGED
@@ -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
|
-
|
8
|
+
plugins.get_hook('pkcs7', :secret_createkeys).call
|
10
9
|
when 'encrypt'
|
11
|
-
|
10
|
+
encrypted = plugins.get_hook('pkcs7', :secret_encrypt).call('plaintext-value' => options[:object])
|
11
|
+
outputter.print_message(encrypted)
|
12
12
|
when 'decrypt'
|
13
|
-
|
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
|
|
data/lib/bolt/transport/winrm.rb
CHANGED
@@ -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
|
-
|
44
|
-
|
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
|
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.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-
|
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
|