bolt 0.13.0 → 0.14.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
  SHA1:
3
- metadata.gz: b45ba6bf81dbfe329d47a503bf505f1eaf3e5449
4
- data.tar.gz: 7d701baa18ad45ddec7cf1cdca86c06e41df1178
3
+ metadata.gz: 6515bd6a3cf63131c23e0809aa98a057030977a3
4
+ data.tar.gz: eee81f558aefb21e761082b04bd73bd631e6685d
5
5
  SHA512:
6
- metadata.gz: 28a20849dbc613f7aea831a27162906e7b70a988b97e75931fc17f6bb9605bc9d731aaa1778182f070188b5f84ba74654e40c95cef405e8987139e93fea419f8
7
- data.tar.gz: c875018a2539e59aedb3c247ec41faad45f86e1aa12ab3dfc6ac7eb6553b1203d6c730596e1d67e4c6e37c2e97a977bb9fd594e1543a1b316a791fddb4fc5a1b
6
+ metadata.gz: 5598b32bf144d8fe0a2cc0601f5ec136235646b182c1a4dc9c4f00aef467f6ea88cdcfcdec25c4fbf88241aa3485d5e9317f34a5d44d8a982f81725678ce8f1b
7
+ data.tar.gz: 2aac3a8c35530eecaf1e57e206d24f8ae3c0f4eb0f53199ff4d14c491cbef873a8b0791843242fb5ff5890393356da0f0f1235b815d093f075c31938cf1d2e4d
data/exe/bolt CHANGED
@@ -10,6 +10,5 @@ begin
10
10
  rescue Bolt::CLIExit
11
11
  exit
12
12
  rescue Bolt::CLIError => e
13
- warn e.message
14
13
  exit e.error_code
15
14
  end
@@ -1,7 +1,7 @@
1
1
  require 'uri'
2
2
  require 'optparse'
3
3
  require 'benchmark'
4
- require 'logger'
4
+ require 'bolt/logger'
5
5
  require 'json'
6
6
  require 'bolt/node'
7
7
  require 'bolt/version'
@@ -109,7 +109,6 @@ HELP
109
109
  }
110
110
  @config = Bolt::Config.new
111
111
  @parser = create_option_parser(@options)
112
- @logger = Logger.new(STDERR)
113
112
  end
114
113
 
115
114
  def create_option_parser(results)
@@ -249,6 +248,7 @@ HELP
249
248
 
250
249
  @config.load_file(options[:configfile])
251
250
  @config.update_from_cli(options)
251
+ Logger.configure(@config)
252
252
  @config.validate
253
253
 
254
254
  # This section handles parsing non-flag options which are
@@ -272,6 +272,9 @@ HELP
272
272
  validate(options)
273
273
 
274
274
  options
275
+ rescue Bolt::CLIError => e
276
+ warn e.message
277
+ raise e
275
278
  end
276
279
 
277
280
  def print_help(mode)
@@ -417,11 +420,11 @@ HELP
417
420
  return
418
421
  end
419
422
 
420
- executor = Bolt::Executor.new(@config, options[:noop])
421
-
422
423
  if options[:mode] == 'plan'
424
+ executor = Bolt::Executor.new(@config, options[:noop], true)
423
425
  execute_plan(executor, options)
424
426
  else
427
+ executor = Bolt::Executor.new(@config, options[:noop])
425
428
  nodes = executor.from_uris(options[:nodes])
426
429
 
427
430
  results = nil
@@ -478,8 +481,6 @@ HELP
478
481
  options[:task_options],
479
482
  &block)
480
483
  end
481
- rescue Puppet::Error
482
- raise Bolt::CLIError, "Exiting because of an error in Puppet code"
483
484
  end
484
485
 
485
486
  def execute_plan(executor, options)
@@ -489,8 +490,6 @@ HELP
489
490
  options[:task_options])
490
491
  end
491
492
  outputter.print_plan(result)
492
- rescue Puppet::Error
493
- raise Bolt::CLIError, "Exiting because of an error in Puppet code"
494
493
  end
495
494
 
496
495
  def validate_file(type, path)
@@ -517,13 +516,24 @@ HELP
517
516
  @outputter ||= Bolt::Outputter.for_format(@config[:format])
518
517
  end
519
518
 
519
+ # Runs a block in a PAL script compiler configured for Bolt.
520
+ # Catches exceptions thrown by the block and re-raises them as Bolt::CLIError.
520
521
  def in_bolt_compiler(opts = [])
521
522
  Puppet.initialize_settings(opts)
522
- Puppet::Pal.in_tmp_environment('bolt', modulepath: [BOLTLIB_PATH] + @config[:modulepath], facts: {}) do |pal|
523
+ r = Puppet::Pal.in_tmp_environment('bolt', modulepath: [BOLTLIB_PATH] + @config[:modulepath], facts: {}) do |pal|
523
524
  pal.with_script_compiler do |compiler|
524
- yield compiler
525
+ begin
526
+ yield compiler
527
+ rescue Puppet::PreformattedError => err
528
+ err.cause
529
+ rescue StandardError => err
530
+ err
531
+ end
525
532
  end
526
533
  end
534
+
535
+ raise Bolt::CLIError, r.message if r.is_a? StandardError
536
+ r
527
537
  end
528
538
 
529
539
  def list_tasks
@@ -534,16 +544,12 @@ HELP
534
544
  [task_name, task_sig.task.description]
535
545
  end
536
546
  end
537
- rescue Puppet::Error
538
- raise Bolt::CLIError, "Failure while reading task metadata"
539
547
  end
540
548
 
541
549
  def list_plans
542
550
  in_bolt_compiler do |compiler|
543
551
  compiler.list_plans.map { |plan| [plan.name] }.sort
544
552
  end
545
- rescue Puppet::Error
546
- raise Bolt::CLIError, "Failure while reading plans"
547
553
  end
548
554
 
549
555
  def get_task_info(task_name)
@@ -552,26 +558,12 @@ HELP
552
558
  end
553
559
  raise Bolt::CLIError, "Could not find task #{task_name} in your modulepath" if task.nil?
554
560
  task.task_hash
555
- rescue Puppet::Error
556
- raise Bolt::CLIError, "Failure while reading task metadata"
557
561
  end
558
562
 
559
563
  def run_task(name, nodes, args, &block)
560
- parse_error = nil
561
- result = in_bolt_compiler do |compiler|
562
- begin
563
- compiler.call_function('run_task', name, nodes, args, &block)
564
- rescue Puppet::ParseError => e
565
- # we assume that the Puppet::ParseError is due to a problem with
566
- # the task and/or its parameters, but since the with_script_compiler
567
- # method rescues these errors and raises different ones instead,
568
- # we save it in a local variable and raise it as Bolt::CLIError
569
- # outside of the block
570
- parse_error = e
571
- end
564
+ in_bolt_compiler do |compiler|
565
+ compiler.call_function('run_task', name, nodes, args, &block)
572
566
  end
573
- raise Bolt::CLIError, parse_error.message if parse_error
574
- result
575
567
  end
576
568
 
577
569
  # Expects to be called with a configured Puppet compiler or error.instance? will fail
@@ -1,4 +1,4 @@
1
- require 'logger'
1
+ require 'bolt/logger'
2
2
  require 'yaml'
3
3
  require 'bolt/cli'
4
4
 
@@ -6,7 +6,6 @@ module Bolt
6
6
  Config = Struct.new(
7
7
  :concurrency,
8
8
  :format,
9
- :log_destination,
10
9
  :log_level,
11
10
  :modulepath,
12
11
  :transport,
@@ -16,12 +15,10 @@ module Bolt
16
15
  DEFAULTS = {
17
16
  concurrency: 100,
18
17
  transport: 'ssh',
19
- format: 'human',
20
- log_level: Logger::WARN,
21
- log_destination: STDERR
18
+ format: 'human'
22
19
  }.freeze
23
20
 
24
- TRANSPORT_OPTIONS = %i[insecure password run_as sudo_password
21
+ TRANSPORT_OPTIONS = %i[insecure password run_as sudo_password extensions
25
22
  key tty tmpdir user connect_timeout cacert
26
23
  token_file orch_task_environment service_url].freeze
27
24
 
@@ -61,7 +58,7 @@ module Bolt
61
58
  if path.nil?
62
59
  found_default = default_paths.select { |p| File.exist?(p) }
63
60
  if found_default.size > 1
64
- logger = Logger.new(self[:log_destination])
61
+ logger = Logger.get_logger
65
62
  logger.warn "Config files found at #{found_default.join(', ')}, using the first"
66
63
  end
67
64
  # Use first found, fall back to first default and try to load even if it didn't exist
@@ -130,6 +127,11 @@ module Bolt
130
127
  if data['winrm']['cacert']
131
128
  self[:transports][:winrm][:cacert] = data['winrm']['cacert']
132
129
  end
130
+ if data['winrm']['extensions']
131
+ # Accept a single entry or a list, ensure each is prefixed with '.'
132
+ self[:transports][:winrm][:extensions] =
133
+ [data['winrm']['extensions']].flatten.map { |ext| ext[0] != '.' ? '.' + ext : ext }
134
+ end
133
135
  end
134
136
 
135
137
  if data['pcp']
@@ -170,12 +172,6 @@ module Bolt
170
172
  self[:transports][transport][key] = options[key] if options[key]
171
173
  end
172
174
  end
173
-
174
- if options[:sudo_password] && self[:transports][:ssh][:run_as].nil?
175
- logger = Logger.new(self[:log_destination])
176
- logger.warn("'--sudo-password will not be used without specifying a" \
177
- "user to escalate to with --run-as")
178
- end
179
175
  end
180
176
 
181
177
  def validate
@@ -187,6 +183,12 @@ module Bolt
187
183
  raise Bolt::CLIError, "Unsupported format: '#{self[:format]}'"
188
184
  end
189
185
 
186
+ if self[:transports][:ssh][:sudo_password] && self[:transports][:ssh][:run_as].nil?
187
+ logger = Logger.get_logger
188
+ logger.warn("--sudo-password will not be used without specifying a " \
189
+ "user to escalate to with --run-as")
190
+ end
191
+
190
192
  self[:transports].each_value do |v|
191
193
  timeout_value = v[:connect_timeout]
192
194
  unless timeout_value.is_a?(Integer) || timeout_value.nil?
@@ -47,7 +47,7 @@ module Bolt
47
47
 
48
48
  def error_nodes
49
49
  result = {}
50
- @result_hash.each_pair { |k, v| result[k] = v if v.is_a?(Error) }
50
+ @result_hash.each_pair { |k, v| result[k] = v if v.is_a?(Puppet::DataTypes::Error) }
51
51
  self.class.new(result, true)
52
52
  end
53
53
 
@@ -56,7 +56,7 @@ module Bolt
56
56
  end
57
57
 
58
58
  def ok
59
- @result_hash.values.none? { |v| v.is_a?(Error) }
59
+ @result_hash.values.none? { |v| v.is_a?(Puppet::DataTypes::Error) }
60
60
  end
61
61
  alias ok? ok
62
62
 
@@ -1,22 +1,20 @@
1
- require 'logger'
1
+ require 'bolt/logger'
2
+ require 'json'
2
3
  require 'concurrent'
3
4
  require 'bolt/result'
4
5
  require 'bolt/config'
5
- require 'bolt/formatter'
6
6
  require 'bolt/notifier'
7
7
 
8
8
  module Bolt
9
9
  class Executor
10
10
  attr_reader :noop
11
11
 
12
- def initialize(config = Bolt::Config.new, noop = nil)
12
+ def initialize(config = Bolt::Config.new, noop = nil, plan_logging = false)
13
13
  @config = config
14
- @logger = Logger.new(config[:log_destination])
15
- @logger.progname = 'executor'
16
- @logger.level = config[:log_level]
17
- @logger.formatter = Bolt::Formatter.new
14
+ @logger = Logger.get_logger(progname: 'executor')
18
15
  @noop = noop
19
16
  @notifier = Bolt::Notifier.new
17
+ @plan_logging = plan_logging
20
18
  end
21
19
 
22
20
  def from_uris(nodes)
@@ -67,36 +65,73 @@ module Bolt
67
65
  results_to_hash(results)
68
66
  end
69
67
 
68
+ def summary(action, object, result)
69
+ fc = result.select { |_, r| r.error }.length
70
+ npl = result.length == 1 ? '' : 's'
71
+ fpl = fc == 1 ? '' : 's'
72
+ "Ran #{action} '#{object}' on #{result.length} node#{npl} with #{fc} failure#{fpl}"
73
+ end
74
+
70
75
  def run_command(nodes, command)
76
+ level = @plan_logging ? Logger::NOTICE : Logger::INFO
77
+ @logger.log(level, "Starting command run '#{command}' on #{nodes.map(&:uri)}")
71
78
  callback = block_given? ? Proc.new : nil
72
79
 
73
- on(nodes, callback) do |node|
74
- node.run_command(command)
80
+ r = on(nodes, callback) do |node|
81
+ @logger.debug("Running command '#{command}' on #{node.uri}")
82
+ node_result = node.run_command(command)
83
+ @logger.debug("Result on #{node.uri}: #{JSON.dump(node_result.to_result)}")
84
+ node_result
75
85
  end
86
+ @logger.log(level, summary('command', command, r))
87
+ r
76
88
  end
77
89
 
78
90
  def run_script(nodes, script, arguments)
91
+ level = @plan_logging ? Logger::NOTICE : Logger::INFO
92
+ @logger.log(level, "Starting script run #{script} on #{nodes.map(&:uri)}")
93
+ @logger.debug("Arguments: #{arguments}")
79
94
  callback = block_given? ? Proc.new : nil
80
95
 
81
- on(nodes, callback) do |node|
82
- node.run_script(script, arguments)
96
+ r = on(nodes, callback) do |node|
97
+ @logger.debug { "Running script '#{script}' on #{node.uri}" }
98
+ node_result = node.run_script(script, arguments)
99
+ @logger.debug("Result on #{node.uri}: #{JSON.dump(node_result.to_result)}")
100
+ node_result
83
101
  end
102
+ @logger.log(level, summary('script', script, r))
103
+ r
84
104
  end
85
105
 
86
106
  def run_task(nodes, task, input_method, arguments)
107
+ level = @plan_logging ? Logger::NOTICE : Logger::INFO
108
+ @logger.log(level, "Starting task #{task} on #{nodes.map(&:uri)}")
109
+ @logger.debug("Arguments: #{arguments} Input method: #{input_method}")
87
110
  callback = block_given? ? Proc.new : nil
88
111
 
89
- on(nodes, callback) do |node|
90
- node.run_task(task, input_method, arguments)
112
+ r = on(nodes, callback) do |node|
113
+ @logger.debug { "Running task run '#{task}' on #{node.uri}" }
114
+ node_result = node.run_task(task, input_method, arguments)
115
+ @logger.debug("Result on #{node.uri}: #{JSON.dump(node_result.to_result)}")
116
+ node_result
91
117
  end
118
+ @logger.log(level, summary('task', task, r))
119
+ r
92
120
  end
93
121
 
94
122
  def file_upload(nodes, source, destination)
123
+ level = @plan_logging ? Logger::NOTICE : Logger::INFO
124
+ @logger.log(level, "Starting file upload from #{source} to #{destination} on #{nodes.map(&:uri)}")
95
125
  callback = block_given? ? Proc.new : nil
96
126
 
97
- on(nodes, callback) do |node|
98
- node.upload(source, destination)
127
+ r = on(nodes, callback) do |node|
128
+ @logger.debug { "Uploading: '#{source}' to #{node.uri}" }
129
+ node_result = node.upload(source, destination)
130
+ @logger.debug("Result on #{node.uri}: #{JSON.dump(node_result.to_result)}")
131
+ node_result
99
132
  end
133
+ @logger.log(level, summary('upload', source, r))
134
+ r
100
135
  end
101
136
 
102
137
  private
@@ -0,0 +1,56 @@
1
+ require 'logger'
2
+ require 'bolt/formatter'
3
+
4
+ class Logger
5
+ send :remove_const, 'SEV_LABEL'
6
+
7
+ SEV_LABEL = {
8
+ 0 => 'DEBUG',
9
+ 1 => 'INFO',
10
+ 2 => 'NOTICE',
11
+ 3 => 'WARN',
12
+ 4 => 'ERROR',
13
+ 5 => 'FATAL',
14
+ 6 => 'ANY'
15
+ }.freeze
16
+
17
+ module Severity
18
+ levels = %w[WARN ERROR FATAL ANY]
19
+ levels.each do |level|
20
+ send(:remove_const, level) if const_defined?(level)
21
+ end
22
+ NOTICE = 2
23
+ WARN = 3
24
+ ERROR = 4
25
+ FATAL = 5
26
+ ANY = 6
27
+ end
28
+
29
+ def notice(progname = nil, &block)
30
+ add(NOTICE, nil, progname, &block)
31
+ end
32
+
33
+ def notice?
34
+ @level <= NOTICE
35
+ end
36
+
37
+ # rubocop:disable Style/ClassVars
38
+ @@config = {
39
+ log_destination: STDERR,
40
+ log_level: NOTICE
41
+ }
42
+
43
+ # Not thread safe call only during startup
44
+ def self.configure(config)
45
+ @@config[:log_level] = config[:log_level] if config[:log_level]
46
+ end
47
+
48
+ def self.get_logger(**conf)
49
+ conf = @@config.merge(conf)
50
+ logger = new(conf[:log_destination])
51
+ logger.level = conf[:log_level]
52
+ logger.progname = conf[:progname] if conf[:progname]
53
+ logger.formatter = Bolt::Formatter.new
54
+ logger
55
+ end
56
+ end
@@ -1,6 +1,5 @@
1
- require 'logger'
1
+ require 'bolt/logger'
2
2
  require 'bolt/node_uri'
3
- require 'bolt/formatter'
4
3
  require 'bolt/result'
5
4
  require 'bolt/config'
6
5
  require 'bolt/target'
@@ -52,17 +51,10 @@ module Bolt
52
51
  @service_url = transport_conf[:service_url]
53
52
  @token_file = transport_conf[:token_file]
54
53
  @orch_task_environment = transport_conf[:orch_task_environment]
54
+ @extensions = transport_conf[:extensions]
55
55
 
56
- @logger = init_logger(config[:log_destination], config[:log_level])
57
- @transport_logger = init_logger(config[:log_destination], Logger::WARN)
58
- end
59
-
60
- def init_logger(destination, level)
61
- logger = Logger.new(destination)
62
- logger.progname = @host
63
- logger.level = level
64
- logger.formatter = Bolt::Formatter.new
65
- logger
56
+ @logger = Logger.get_logger(progname: @host)
57
+ @transport_logger = Logger.get_logger(progname: @host, log_level: Logger::WARN)
66
58
  end
67
59
 
68
60
  def upload(source, destination)
@@ -76,12 +68,10 @@ module Bolt
76
68
  end
77
69
 
78
70
  def run_command(command)
79
- @logger.info { "Running command: #{command}" }
80
71
  _run_command(command)
81
72
  end
82
73
 
83
74
  def run_script(script, arguments)
84
- @logger.info { "Running script: #{script}" }
85
75
  _run_script(script, arguments)
86
76
  end
87
77
 
@@ -82,13 +82,13 @@ module Bolt
82
82
  )
83
83
  end
84
84
  elsif data =~ /^#{@user} is not in the sudoers file\./
85
- @logger.info { data }
85
+ @logger.debug { data }
86
86
  raise Bolt::Node::EscalateError.new(
87
87
  "User #{@user} does not have sudo permission on #{@uri}",
88
88
  'SUDO_DENIED'
89
89
  )
90
90
  elsif data =~ /^Sorry, try again\./
91
- @logger.info { data }
91
+ @logger.debug { data }
92
92
  raise Bolt::Node::EscalateError.new(
93
93
  "Sudo password for user #{@user} not recognized on #{@uri}",
94
94
  'BAD_PASSWORD'
@@ -260,9 +260,6 @@ SCRIPT
260
260
  end
261
261
 
262
262
  def _run_script(script, arguments)
263
- @logger.info { "Running script '#{script}'" }
264
- @logger.debug { "arguments: #{arguments}" }
265
-
266
263
  with_remote_file(script) do |remote_path|
267
264
  output = execute("'#{remote_path}' #{Shellwords.join(arguments)}",
268
265
  sudoable: true)
@@ -278,9 +275,6 @@ SCRIPT
278
275
  export_args = {}
279
276
  stdin, output = nil
280
277
 
281
- @logger.info { "Running task '#{task}'" }
282
- @logger.debug { "arguments: #{arguments}\ninput_method: #{input_method}" }
283
-
284
278
  if STDIN_METHODS.include?(input_method)
285
279
  stdin = JSON.dump(arguments)
286
280
  end
@@ -2,6 +2,7 @@ require 'winrm'
2
2
  require 'winrm-fs'
3
3
  require 'bolt/result'
4
4
  require 'base64'
5
+ require 'set'
5
6
 
6
7
  module Bolt
7
8
  class WinRM < Node
@@ -16,6 +17,8 @@ module Bolt
16
17
 
17
18
  def initialize(host, port, user, password, **kwargs)
18
19
  super(host, port, user, password, **kwargs)
20
+ @extensions = DEFAULT_EXTENSIONS.to_set.merge(@extensions || [])
21
+ @logger.debug { "WinRM initialized for #{@extensions.to_a} extensions" }
19
22
  end
20
23
 
21
24
  def connect
@@ -401,7 +404,7 @@ exit $(Invoke-Interpreter @invokeArgs)
401
404
  PS
402
405
  end
403
406
 
404
- VALID_EXTENSIONS = ['.ps1', '.rb', '.pp'].freeze
407
+ DEFAULT_EXTENSIONS = ['.ps1', '.rb', '.pp'].freeze
405
408
 
406
409
  PS_ARGS = %w[
407
410
  -NoProfile -NonInteractive -NoLogo -ExecutionPolicy Bypass
@@ -428,6 +431,12 @@ PS
428
431
  'puppet.bat',
429
432
  ['apply', "\"#{path}\""]
430
433
  ]
434
+ else
435
+ # Run the script via cmd, letting Windows extension handling determine how
436
+ [
437
+ 'cmd.exe',
438
+ ['/c', "\"#{path}\""]
439
+ ]
431
440
  end
432
441
  end
433
442
 
@@ -440,7 +449,6 @@ PS
440
449
  end
441
450
 
442
451
  def write_remote_file(source, destination)
443
- @logger.debug { "Uploading #{source} to #{destination}" }
444
452
  fs = ::WinRM::FS::FileManager.new(@connection)
445
453
  # TODO: raise FileError here if this fails
446
454
  fs.upload(source, destination)
@@ -463,10 +471,13 @@ PS
463
471
 
464
472
  def with_remote_file(file)
465
473
  ext = File.extname(file)
466
- ext = VALID_EXTENSIONS.include?(ext) ? ext : '.ps1'
467
- file_base = File.basename(file, '.*')
474
+ unless @extensions.include?(ext)
475
+ raise FileError.new("File extension #{ext} is not enabled, "\
476
+ "to run it please add to 'winrm: extensions'", 'FILETYPE_ERROR')
477
+ end
478
+ file_base = File.basename(file)
468
479
  dir = make_tempdir
469
- dest = "#{dir}\\#{file_base}#{ext}"
480
+ dest = "#{dir}\\#{file_base}"
470
481
  begin
471
482
  write_remote_file(file, dest)
472
483
  shell_init
@@ -488,7 +499,6 @@ PS
488
499
  end
489
500
 
490
501
  def _run_script(script, arguments)
491
- @logger.info { "Running script '#{script}'" }
492
502
  with_remote_file(script) do |remote_path|
493
503
  if powershell_file?(remote_path)
494
504
  mapped_args = arguments.map do |a|
@@ -523,9 +533,6 @@ catch
523
533
  end
524
534
 
525
535
  def _run_task(task, input_method, arguments)
526
- @logger.info { "Running task '#{task}'" }
527
- @logger.debug { "arguments: #{arguments}\ninput_method: #{input_method}" }
528
-
529
536
  if STDIN_METHODS.include?(input_method)
530
537
  stdin = JSON.dump(arguments)
531
538
  end
@@ -136,7 +136,9 @@ module Bolt
136
136
  end
137
137
  end
138
138
 
139
- def fatal_error(e); end
139
+ def fatal_error(e)
140
+ @stream.puts(colorize(:red, e.message))
141
+ end
140
142
  end
141
143
 
142
144
  def print_message(message)
@@ -1,3 +1,3 @@
1
1
  module Bolt
2
- VERSION = '0.13.0'.freeze
2
+ VERSION = '0.14.0'.freeze
3
3
  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: 0.13.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-05 00:00:00.000000000 Z
11
+ date: 2018-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -312,6 +312,7 @@ files:
312
312
  - lib/bolt/execution_result.rb
313
313
  - lib/bolt/executor.rb
314
314
  - lib/bolt/formatter.rb
315
+ - lib/bolt/logger.rb
315
316
  - lib/bolt/node.rb
316
317
  - lib/bolt/node/errors.rb
317
318
  - lib/bolt/node/orch.rb
@@ -1577,7 +1578,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1577
1578
  version: '0'
1578
1579
  requirements: []
1579
1580
  rubyforge_project:
1580
- rubygems_version: 2.5.1
1581
+ rubygems_version: 2.6.12
1581
1582
  signing_key:
1582
1583
  specification_version: 4
1583
1584
  summary: Execute commands remotely over SSH and WinRM