puppet-debugger 0.17.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab-ci.yml +12 -26
  3. data/.rubocop.yml +64 -232
  4. data/.rubocop_todo.yml +89 -147
  5. data/.vscode/launch.json +15 -0
  6. data/CHANGELOG.md +29 -0
  7. data/Gemfile +9 -6
  8. data/README.md +27 -14
  9. data/Rakefile +11 -12
  10. data/bin/pdb +1 -1
  11. data/lib/awesome_print/ext/awesome_puppet.rb +10 -8
  12. data/lib/plugins/puppet-debugger/input_responders/benchmark.rb +5 -4
  13. data/lib/plugins/puppet-debugger/input_responders/classes.rb +14 -2
  14. data/lib/plugins/puppet-debugger/input_responders/classification.rb +4 -2
  15. data/lib/plugins/puppet-debugger/input_responders/commands.rb +18 -18
  16. data/lib/plugins/puppet-debugger/input_responders/datatypes.rb +22 -6
  17. data/lib/plugins/puppet-debugger/input_responders/environment.rb +4 -2
  18. data/lib/plugins/puppet-debugger/input_responders/exit.rb +5 -3
  19. data/lib/plugins/puppet-debugger/input_responders/facterdb_filter.rb +4 -2
  20. data/lib/plugins/puppet-debugger/input_responders/facts.rb +4 -2
  21. data/lib/plugins/puppet-debugger/input_responders/functions.rb +34 -32
  22. data/lib/plugins/puppet-debugger/input_responders/help.rb +4 -2
  23. data/lib/plugins/puppet-debugger/input_responders/krt.rb +4 -2
  24. data/lib/plugins/puppet-debugger/input_responders/play.rb +22 -24
  25. data/lib/plugins/puppet-debugger/input_responders/reset.rb +5 -3
  26. data/lib/plugins/puppet-debugger/input_responders/resources.rb +16 -7
  27. data/lib/plugins/puppet-debugger/input_responders/set.rb +34 -32
  28. data/lib/plugins/puppet-debugger/input_responders/stacktrace.rb +31 -0
  29. data/lib/plugins/puppet-debugger/input_responders/types.rb +6 -2
  30. data/lib/plugins/puppet-debugger/input_responders/vars.rb +8 -7
  31. data/lib/plugins/puppet-debugger/input_responders/whereami.rb +5 -3
  32. data/lib/puppet-debugger/cli.rb +129 -91
  33. data/lib/puppet-debugger/code/code_file.rb +13 -14
  34. data/lib/puppet-debugger/code/code_range.rb +5 -3
  35. data/lib/puppet-debugger/code/loc.rb +1 -1
  36. data/lib/puppet-debugger/debugger_code.rb +2 -0
  37. data/lib/puppet-debugger/hooks.rb +15 -16
  38. data/lib/puppet-debugger/input_responder_plugin.rb +54 -52
  39. data/lib/puppet-debugger/monkey_patches.rb +4 -1
  40. data/lib/puppet-debugger/plugin_test_helper.rb +9 -8
  41. data/lib/puppet-debugger/support.rb +44 -18
  42. data/lib/puppet-debugger/support/environment.rb +6 -5
  43. data/lib/puppet-debugger/support/errors.rb +25 -27
  44. data/lib/puppet-debugger/support/facts.rb +5 -5
  45. data/lib/puppet-debugger/support/node.rb +4 -7
  46. data/lib/puppet-debugger/support/scope.rb +29 -0
  47. data/lib/puppet-debugger/trollop.rb +38 -31
  48. data/lib/puppet-debugger/version.rb +1 -1
  49. data/lib/puppet/application/debugger.rb +151 -126
  50. data/output.json +1 -0
  51. data/puppet-debugger.gemspec +18 -15
  52. data/spec/awesome_print/ext/awesome_puppet_spec.rb +30 -30
  53. data/spec/fixtures/pe-xl-core-0.puppet.vm.json +1 -0
  54. data/spec/fixtures/sample_start_debugger.pp +3 -2
  55. data/spec/hooks_spec.rb +33 -35
  56. data/spec/input_responder_plugin_spec.rb +7 -6
  57. data/spec/input_responders/benchmark_spec.rb +3 -1
  58. data/spec/input_responders/classes_spec.rb +12 -13
  59. data/spec/input_responders/classification_spec.rb +4 -2
  60. data/spec/input_responders/commands_spec.rb +2 -0
  61. data/spec/input_responders/datatypes_spec.rb +8 -2
  62. data/spec/input_responders/environment_spec.rb +2 -0
  63. data/spec/input_responders/exit_spec.rb +9 -11
  64. data/spec/input_responders/facterdb_filter_spec.rb +2 -0
  65. data/spec/input_responders/facts_spec.rb +2 -0
  66. data/spec/input_responders/functions_spec.rb +30 -28
  67. data/spec/input_responders/help_spec.rb +5 -3
  68. data/spec/input_responders/krt_spec.rb +3 -1
  69. data/spec/input_responders/play_spec.rb +10 -20
  70. data/spec/input_responders/reset_spec.rb +2 -0
  71. data/spec/input_responders/resources_spec.rb +7 -1
  72. data/spec/input_responders/set_spec.rb +3 -1
  73. data/spec/input_responders/stacktrace_spec.rb +15 -0
  74. data/spec/input_responders/types_spec.rb +2 -0
  75. data/spec/input_responders/vars_spec.rb +4 -4
  76. data/spec/input_responders/whereami_spec.rb +2 -0
  77. data/spec/pdb_spec.rb +0 -9
  78. data/spec/puppet/application/debugger_spec.rb +35 -17
  79. data/spec/puppet_debugger_spec.rb +81 -84
  80. data/spec/remote_node_spec.rb +1 -5
  81. data/spec/spec_helper.rb +22 -18
  82. data/spec/support_spec.rb +3 -5
  83. data/test_matrix.rb +1 -1
  84. metadata +54 -21
@@ -9,8 +9,6 @@ module PuppetDebugger
9
9
  end
10
10
  end
11
11
 
12
-
13
-
14
12
  class FatalError < Error
15
13
  end
16
14
 
@@ -22,9 +20,9 @@ module PuppetDebugger
22
20
 
23
21
  class ConnectError < Error
24
22
  def message
25
- out = <<-EOF
26
- #{data[:message]}
27
- EOF
23
+ <<~OUT
24
+ #{data[:message]}
25
+ OUT
28
26
  end
29
27
  end
30
28
 
@@ -36,9 +34,9 @@ EOF
36
34
 
37
35
  class UndefinedNode < FatalError
38
36
  def message
39
- out = <<-EOF
40
- Cannot find node with name: #{data[:name]} on remote server
41
- EOF
37
+ <<~OUT
38
+ Cannot find node with name: #{data[:name]} on remote server
39
+ OUT
42
40
  end
43
41
  end
44
42
 
@@ -48,36 +46,36 @@ Cannot find node with name: #{data[:name]} on remote server
48
46
 
49
47
  class NoClassError < FatalError
50
48
  def message
51
- out = <<-EOF
52
- #{data[:message]}
53
- You are missing puppet classes that are required for compilation.
54
- Please ensure these classes are installed on this machine in any of the following paths:
55
- #{data[:default_modules_paths]}
56
- EOF
49
+ <<~OUT
50
+ #{data[:message]}
51
+ You are missing puppet classes that are required for compilation.
52
+ Please ensure these classes are installed on this machine in any of the following paths:
53
+ #{data[:default_modules_paths]}
54
+ OUT
57
55
  end
58
56
  end
59
57
 
60
58
  class NodeDefinitionError < FatalError
61
59
  def message
62
- out = <<-EOF
63
- You are missing a default node definition in your site.pp that is required for compilation.
64
- Please ensure you have at least the following default node definition
65
- node default {
66
- # include classes here
67
- }
68
- in your #{data[:default_site_manifest]} file.
69
- EOF
60
+ out = <<~OUT
61
+ You are missing a default node definition in your site.pp that is required for compilation.
62
+ Please ensure you have at least the following default node definition
63
+ node default {
64
+ # include classes here
65
+ }
66
+ in your #{data[:default_site_manifest]} file.
67
+ OUT
70
68
  out.fatal
71
69
  end
72
70
  end
73
71
 
74
72
  class AuthError < FatalError
75
73
  def message
76
- out = <<-EOF
77
- #{data[:message]}
78
- You will need to edit your auth.conf or conf.d/auth.conf (puppetserver) to allow node calls.
79
- EOF
80
- end
74
+ <<~OUT
75
+ #{data[:message]}
76
+ You will need to edit your auth.conf or conf.d/auth.conf (puppetserver) to allow node calls.
77
+ OUT
78
+ end
81
79
  end
82
80
  end
83
81
  end
@@ -46,11 +46,11 @@ module PuppetDebugger
46
46
  def node_facts
47
47
  node_facts = FacterDB.get_facts(dynamic_facterdb_filter).first
48
48
  if node_facts.nil?
49
- message = <<-EOS
50
- Using filter: #{dynamic_facterdb_filter}
51
- Bad FacterDB filter, please change the filter so it returns a result set.
52
- See https://github.com/camptocamp/facterdb/#with-a-string-filter
53
- EOS
49
+ message = <<~OUT
50
+ Using filter: #{dynamic_facterdb_filter}
51
+ Bad FacterDB filter, please change the filter so it returns a result set.
52
+ See https://github.com/camptocamp/facterdb/#with-a-string-filter
53
+ OUT
54
54
  raise PuppetDebugger::Exception::BadFilter, message: message
55
55
  end
56
56
  # fix for when --show-legacy facts are not part of the facter 3 fact set
@@ -8,8 +8,6 @@ module PuppetDebugger
8
8
  # creates a node object using defaults or gets the remote node
9
9
  # object if the remote_node_name is defined
10
10
  def create_node
11
- Puppet[:trusted_server_facts] = true if Puppet.version.to_f >= 4.1 && Puppet.version.to_f < 6.0
12
-
13
11
  if remote_node_name
14
12
  # refetch
15
13
  node_obj = set_node_from_name(remote_node_name)
@@ -34,6 +32,7 @@ module PuppetDebugger
34
32
  # Collect our facts.
35
33
  facts = Puppet::Node::Facts.indirection.find(Puppet[:node_name_value])
36
34
  raise "Could not find facts for #{Puppet[:node_name_value]}" unless facts
35
+
37
36
  Puppet[:node_name_value] = facts.values[Puppet[:node_name_fact]]
38
37
  facts.name = Puppet[:node_name_value]
39
38
  end
@@ -41,6 +40,7 @@ module PuppetDebugger
41
40
  # Find our Node
42
41
  node = Puppet::Node.indirection.find(Puppet[:node_name_value])
43
42
  raise "Could not find node #{Puppet[:node_name_value]}" unless node
43
+
44
44
  # Merge in the facts.
45
45
  node.merge(facts.values) if facts
46
46
  end
@@ -93,11 +93,8 @@ module PuppetDebugger
93
93
  def set_node_from_name(name)
94
94
  out_buffer.puts "Fetching node #{name}"
95
95
  remote_node = get_remote_node(name)
96
- if remote_node && remote_node.parameters.empty?
97
- remote_node_name = nil # clear out the remote name
98
- raise PuppetDebugger::Exception::UndefinedNode, name: remote_node.name
99
- end
100
- remote_node_name = remote_node.name
96
+ raise PuppetDebugger::Exception::UndefinedNode, name: remote_node.name if remote_node&.parameters&.empty?
97
+
101
98
  node_object = convert_remote_node(remote_node)
102
99
  set_node(node_object)
103
100
  end
@@ -8,6 +8,35 @@ module PuppetDebugger
8
8
  @scope = value
9
9
  end
10
10
 
11
+ def catalog
12
+ @catalog || scope.compiler.catalog
13
+ end
14
+
15
+ def get_catalog_text(catalog)
16
+ return nil unless catalog
17
+
18
+ Puppet::FileSystem.read(catalog, encoding: 'utf-8')
19
+ end
20
+
21
+ def set_catalog(catalog_file)
22
+ return unless catalog_file
23
+
24
+ catalog_text = get_catalog_text(catalog_file)
25
+ scope # required
26
+ Puppet.override({ current_environment: environment }, _('For puppet debugger')) do
27
+ format = Puppet::Resource::Catalog.default_format
28
+ begin
29
+ c = Puppet::Resource::Catalog.convert_from(format, catalog_text)
30
+ rescue StandardError => e
31
+ raise Puppet::Error, format(_('Could not deserialize catalog from %{format}: %{detail}'), format: format, detail: e), e.backtrace
32
+ end
33
+ # Resolve all deferred values and replace them / mutate the catalog
34
+ # Puppet 6 only
35
+ Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(node.facts, c) if Gem::Version.new(Puppet.version) >= Gem::Version.new('6.0.0')
36
+ @catalog = c
37
+ end
38
+ end
39
+
11
40
  # @return [Puppet::Pops::Scope] - returns a puppet scope object
12
41
  def scope
13
42
  @scope ||= create_scope
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # lib/trollop.rb -- trollop command-line processing library
3
4
  # Copyright (c) 2008-2014 William Morgan.
4
5
  # Copyright (c) 2014 Red Hat, Inc.
@@ -33,10 +34,10 @@ module Trollop
33
34
  end
34
35
 
35
36
  ## Regex for floating point numbers
36
- FLOAT_RE = /^-?((\d+(\.\d+)?)|(\.\d+))([eE][-+]?[\d]+)?$/
37
+ FLOAT_RE = /^-?((\d+(\.\d+)?)|(\.\d+))([eE][-+]?[\d]+)?$/.freeze
37
38
 
38
39
  ## Regex for parameters
39
- PARAM_RE = /^-(-|\.$|[^\d\.])/
40
+ PARAM_RE = /^-(-|\.$|[^\d\.])/.freeze
40
41
 
41
42
  ## The commandline parser. In typical usage, the methods in this class
42
43
  ## will be handled internally by Trollop::options. In this case, only the
@@ -50,24 +51,24 @@ module Trollop
50
51
  class Parser
51
52
  ## The set of values that indicate a flag option when passed as the
52
53
  ## +:type+ parameter of #opt.
53
- FLAG_TYPES = [:flag, :bool, :boolean].freeze
54
+ FLAG_TYPES = %i[flag bool boolean].freeze
54
55
 
55
56
  ## The set of values that indicate a single-parameter (normal) option when
56
57
  ## passed as the +:type+ parameter of #opt.
57
58
  ##
58
59
  ## A value of +io+ corresponds to a readable IO resource, including
59
60
  ## a filename, URI, or the strings 'stdin' or '-'.
60
- SINGLE_ARG_TYPES = [:int, :integer, :string, :double, :float, :io, :date].freeze
61
+ SINGLE_ARG_TYPES = %i[int integer string double float io date].freeze
61
62
 
62
63
  ## The set of values that indicate a multiple-parameter option (i.e., that
63
64
  ## takes multiple space-separated values on the commandline) when passed as
64
65
  ## the +:type+ parameter of #opt.
65
- MULTI_ARG_TYPES = [:ints, :integers, :strings, :doubles, :floats, :ios, :dates].freeze
66
+ MULTI_ARG_TYPES = %i[ints integers strings doubles floats ios dates].freeze
66
67
 
67
68
  ## The complete set of legal values for the +:type+ parameter of #opt.
68
69
  TYPES = FLAG_TYPES + SINGLE_ARG_TYPES + MULTI_ARG_TYPES
69
70
 
70
- INVALID_SHORT_ARG_REGEX = /[\d-]/ #:nodoc:
71
+ INVALID_SHORT_ARG_REGEX = /[\d-]/.freeze #:nodoc:
71
72
 
72
73
  ## The values from the commandline that were not interpreted by #parse.
73
74
  attr_reader :leftovers
@@ -151,8 +152,7 @@ module Trollop
151
152
  when :doubles then :floats
152
153
  when Class
153
154
  case opts[:type].name
154
- when 'TrueClass',
155
- 'FalseClass' then :flag
155
+ when 'TrueClass', 'FalseClass' then :flag
156
156
  when 'String' then :string
157
157
  when 'Integer' then :int
158
158
  when 'Float' then :float
@@ -164,6 +164,7 @@ module Trollop
164
164
  when nil then nil
165
165
  else
166
166
  raise ArgumentError, "unsupported argument type '#{opts[:type]}'" unless TYPES.include?(opts[:type])
167
+
167
168
  opts[:type]
168
169
  end
169
170
 
@@ -175,14 +176,13 @@ module Trollop
175
176
  opts[:default].first
176
177
  else
177
178
  opts[:default]
178
- end
179
+ end
179
180
 
180
181
  type_from_default =
181
182
  case disambiguated_default
182
183
  when Integer then :int
183
184
  when Numeric then :float
184
- when TrueClass,
185
- FalseClass then :flag
185
+ when TrueClass, FalseClass then :flag
186
186
  when String then :string
187
187
  when IO then :io
188
188
  when Date then :date
@@ -190,6 +190,7 @@ module Trollop
190
190
  if opts[:default].empty?
191
191
  if opts[:type]
192
192
  raise ArgumentError, 'multiple argument type must be plural' unless MULTI_ARG_TYPES.include?(opts[:type])
193
+
193
194
  nil
194
195
  else
195
196
  raise ArgumentError, "multiple argument type cannot be deduced from an empty array for '#{opts[:default][0].class.name}'"
@@ -220,7 +221,7 @@ module Trollop
220
221
  when /^--([^-].*)$/ then Regexp.last_match(1)
221
222
  when /^[^-]/ then opts[:long]
222
223
  else raise ArgumentError, "invalid long option name #{opts[:long].inspect}"
223
- end
224
+ end
224
225
  raise ArgumentError, "long option name #{opts[:long].inspect} is already taken; please specify a (different) :long" if @long[opts[:long]]
225
226
 
226
227
  ## fill in :short
@@ -229,7 +230,7 @@ module Trollop
229
230
  when /^-(.)$/ then Regexp.last_match(1)
230
231
  when nil, :none, /^.$/ then opts[:short]
231
232
  else raise ArgumentError, "invalid short option name '#{opts[:short].inspect}'"
232
- end
233
+ end
233
234
 
234
235
  if opts[:short]
235
236
  raise ArgumentError, "short option name #{opts[:short].inspect} is already taken; please specify a (different) :short" if @short[opts[:short]]
@@ -255,21 +256,21 @@ module Trollop
255
256
  ## Sets the version string. If set, the user can request the version
256
257
  ## on the commandline. Should probably be of the form "<program name>
257
258
  ## <version number>".
258
- def version(s = nil)
259
- s ? @version = s : @version
259
+ def version(value = nil)
260
+ value ? @version = value : @version
260
261
  end
261
262
 
262
263
  ## Sets the usage string. If set the message will be printed as the
263
264
  ## first line in the help (educate) output and ending in two new
264
265
  ## lines.
265
- def usage(s = nil)
266
- s ? @usage = s : @usage
266
+ def usage(value = nil)
267
+ value ? @usage = value : @usage
267
268
  end
268
269
 
269
270
  ## Adds a synopsis (command summary description) right below the
270
271
  ## usage line, or as the first line if usage isn't specified.
271
- def synopsis(s = nil)
272
- s ? @synopsis = s : @synopsis
272
+ def synopsis(value = nil)
273
+ value ? @synopsis = value : @synopsis
273
274
  end
274
275
 
275
276
  ## Adds text to the help display. Can be interspersed with calls to
@@ -347,22 +348,20 @@ module Trollop
347
348
  ["--#{Regexp.last_match(1)}", true]
348
349
  else
349
350
  [arg, false]
350
- end
351
+ end
351
352
 
352
353
  sym = case arg
353
354
  when /^-([^-])$/ then @short[Regexp.last_match(1)]
354
355
  when /^--([^-]\S*)$/ then @long[Regexp.last_match(1)] || @long["no-#{Regexp.last_match(1)}"]
355
356
  else raise CommandlineError, "invalid argument syntax: '#{arg}'"
356
- end
357
+ end
357
358
 
358
359
  sym = nil if arg =~ /--no-/ # explicitly invalidate --no-no- arguments
359
360
 
360
361
  next 0 if ignore_invalid_options && !sym
361
362
  raise CommandlineError, "unknown argument '#{arg}'" unless sym
362
363
 
363
- if given_args.include?(sym) && !@specs[sym][:multi]
364
- raise CommandlineError, "option '#{arg}' specified multiple times"
365
- end
364
+ raise CommandlineError, "option '#{arg}' specified multiple times" if given_args.include?(sym) && !@specs[sym][:multi]
366
365
 
367
366
  given_args[sym] ||= {}
368
367
  given_args[sym][:arg] = arg
@@ -396,9 +395,13 @@ module Trollop
396
395
 
397
396
  case type
398
397
  when :depends
399
- syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}" unless given_args.include? sym }
398
+ syms.each do |sym|
399
+ raise CommandlineError, "--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}" unless given_args.include? sym
400
+ end
400
401
  when :conflicts
401
- syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}" if given_args.include?(sym) && (sym != constraint_sym) }
402
+ syms.each do |sym|
403
+ raise CommandlineError, "--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}" if given_args.include?(sym) && (sym != constraint_sym)
404
+ end
402
405
  end
403
406
  end
404
407
 
@@ -413,6 +416,7 @@ module Trollop
413
416
  opts = @specs[sym]
414
417
  if params.empty? && opts[:type] != :flag
415
418
  raise CommandlineError, "option '#{arg}' needs a parameter" unless opts[:default]
419
+
416
420
  params << (opts[:default].is_a?(Array) ? opts[:default].clone : [opts[:default]])
417
421
  end
418
422
 
@@ -527,7 +531,7 @@ module Trollop
527
531
  spec[:default].join(', ')
528
532
  else
529
533
  spec[:default].to_s
530
- end
534
+ end
531
535
 
532
536
  if spec[:default]
533
537
  if spec[:desc] =~ /\.$/
@@ -553,7 +557,7 @@ module Trollop
553
557
  end
554
558
  else
555
559
  80
556
- end
560
+ end
557
561
  end
558
562
 
559
563
  def legacy_width
@@ -580,15 +584,15 @@ module Trollop
580
584
  ## The per-parser version of Trollop::die (see that for documentation).
581
585
  def die(arg, msg = nil, error_code = nil)
582
586
  if msg
583
- $stderr.puts "Error: argument --#{@specs[arg][:long]} #{msg}."
587
+ warn "Error: argument --#{@specs[arg][:long]} #{msg}."
584
588
  else
585
- $stderr.puts "Error: #{arg}."
589
+ warn "Error: #{arg}."
586
590
  end
587
591
  if @educate_on_error
588
592
  $stderr.puts
589
593
  educate $stderr
590
594
  else
591
- $stderr.puts 'Try --help for help.'
595
+ warn 'Try --help for help.'
592
596
  end
593
597
  exit(error_code || -1)
594
598
  end
@@ -602,6 +606,7 @@ module Trollop
602
606
 
603
607
  until i >= args.length
604
608
  return remains += args[i..-1] if @stop_words.member? args[i]
609
+
605
610
  case args[i]
606
611
  when /^--$/ # arg terminator
607
612
  return remains += args[(i + 1)..-1]
@@ -662,11 +667,13 @@ module Trollop
662
667
 
663
668
  def parse_integer_parameter(param, arg)
664
669
  raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^-?[\d_]+$/
670
+
665
671
  param.to_i
666
672
  end
667
673
 
668
674
  def parse_float_parameter(param, arg)
669
675
  raise CommandlineError, "option '#{arg}' needs a floating-point number" unless param =~ FLOAT_RE
676
+
670
677
  param.to_f
671
678
  end
672
679
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PuppetDebugger
4
- VERSION = "0.17.0"
4
+ VERSION = '1.2.0'
5
5
  end
@@ -1,186 +1,199 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "puppet/application"
4
- require "optparse"
5
- require "puppet/util/command_line"
3
+ require 'puppet/application'
4
+ require 'optparse'
5
+ require 'puppet/util/command_line'
6
6
 
7
7
  class Puppet::Application::Debugger < Puppet::Application
8
8
  attr_reader :use_stdin
9
9
 
10
- option("--execute EXECUTE", "-e") do |arg|
10
+ option('--execute EXECUTE', '-e') do |arg|
11
11
  options[:code] = arg
12
12
  end
13
13
 
14
- option("--facterdb-filter FILTER") do |arg|
14
+ option('--facterdb-filter FILTER') do |arg|
15
15
  options[:use_facterdb] = true unless options[:node_name]
16
- ENV["DEBUGGER_FACTERDB_FILTER"] = arg if arg
16
+ ENV['DEBUGGER_FACTERDB_FILTER'] = arg if arg
17
17
  end
18
18
 
19
- option("--test") do |_arg|
19
+ option('--test') do |_arg|
20
20
  options[:quiet] = true
21
21
  options[:run_once] = true
22
22
  @use_stdin = true
23
23
  end
24
24
 
25
- option("--no-facterdb") { |_arg| options[:use_facterdb] = false }
25
+ option('--no-facterdb') { |_arg| options[:use_facterdb] = false }
26
26
 
27
- option("--log-level LEVEL", "-l") do |arg|
27
+ option('--log-level LEVEL', '-l') do |arg|
28
28
  Puppet::Util::Log.level = arg.to_sym
29
29
  end
30
30
 
31
- option("--quiet", "-q") { |_arg| options[:quiet] = true }
31
+ option('--catalog catalog', '-c catalog') do |arg|
32
+ options[:catalog] = arg
33
+ end
34
+
35
+ option('--quiet', '-q') { |_arg| options[:quiet] = true }
32
36
 
33
- option("--play URL", "-p") do |arg|
37
+ option('--play URL', '-p') do |arg|
34
38
  options[:play] = arg
35
39
  end
36
40
 
37
- option("--stdin", "-s") { |_arg| @use_stdin = true }
41
+ option('--stdin', '-s') { |_arg| @use_stdin = true }
38
42
 
39
- option("--run-once", "-r") { |_arg| options[:run_once] = true }
43
+ option('--run-once', '-r') { |_arg| options[:run_once] = true }
40
44
 
41
- option("--node-name CERTNAME", "-n") do |arg|
45
+ option('--node-name CERTNAME', '-n') do |arg|
42
46
  options[:use_facterdb] = false
43
47
  options[:node_name] = arg
44
48
  end
45
49
 
46
50
  def help
47
- <<-HELP
51
+ <<~HELP
48
52
 
49
- puppet-debugger(8) -- Starts a debugger session using the puppet-debugger tool
50
- ========
53
+ puppet-debugger(8) -- Starts a debugger session using the puppet-debugger tool
54
+ ========
51
55
 
52
- SYNOPSIS
53
- --------
54
- A interactive command line tool for evaluating the puppet language and debugging
55
- puppet code.
56
+ SYNOPSIS
57
+ --------
58
+ A interactive command line tool for evaluating the puppet language and debugging
59
+ puppet code.
56
60
 
57
- USAGE
58
- -----
59
- puppet debugger [--help] [--version] [-e|--execute CODE] [--facterdb-filter FILTER]
60
- [--test] [--no-facterdb] [-q|--quiet] [-p|--play URL] [-s|--stdin]
61
- [-r|--run-once] [-n|--node-name CERTNAME]
61
+ USAGE
62
+ -----
63
+ puppet debugger [--help] [--version] [-e|--execute CODE] [--facterdb-filter FILTER]
64
+ [--test] [--no-facterdb] [-q|--quiet] [-p|--play URL] [-s|--stdin]
65
+ [-r|--run-once] [-n|--node-name CERTNAME]
62
66
 
63
67
 
64
- DESCRIPTION
65
- -----------
66
- A interactive command line tool for evaluating the puppet language and debugging
67
- puppet code.
68
+ DESCRIPTION
69
+ -----------
70
+ A interactive command line tool for evaluating the puppet language and debugging
71
+ puppet code.
72
+
73
+ USAGE WITH DEBUG MODULE
74
+ -----------------------
75
+ Use the puppet debugger in conjunction with the debug::break() puppet function
76
+ to pry into your code during compilation. Get immediate insight in how the puppet4
77
+ languge works during the execution of your code.
68
78
 
69
- USAGE WITH DEBUG MODULE
70
- -----------------------
71
- Use the puppet debugger in conjunction with the debug::break() puppet function
72
- to pry into your code during compilation. Get immediate insight in how the puppet4
73
- languge works during the execution of your code.
79
+ To use the break function install the module via: puppet module install nwops/debug
74
80
 
75
- To use the break function install the module via: puppet module install nwops/debug
81
+ Now place the debug::break() function anywhere in your code to
76
82
 
77
- Now place the debug::break() function anywhere in your code to
83
+ Example:
84
+ puppet debugger -e '$abs_vars = [-11,-22,-33].map | Integer $num | { debug::break() ; notice($num) }'
78
85
 
79
- Example:
80
- puppet debugger -e '$abs_vars = [-11,-22,-33].map | Integer $num | { debug::break() ; notice($num) }'
86
+ See: https://github.com/nwops/puppet-debug
87
+ OPTIONS
88
+ -------
89
+ Note that any setting that's valid in the configuration
90
+ file is also a valid long argument. For example, 'server' is a valid
91
+ setting, so you can specify '--server <servername>' as
92
+ an argument.
81
93
 
82
- See: https://github.com/nwops/puppet-debug
83
- OPTIONS
84
- -------
85
- Note that any setting that's valid in the configuration
86
- file is also a valid long argument. For example, 'server' is a valid
87
- setting, so you can specify '--server <servername>' as
88
- an argument.
94
+ See the configuration file documentation at
95
+ http://docs.puppetlabs.com/references/stable/configuration.html for the
96
+ full list of acceptable parameters. A commented list of all
97
+ configuration options can also be generated by running puppet debugger with
98
+ '--genconfig'.
89
99
 
90
- See the configuration file documentation at
91
- http://docs.puppetlabs.com/references/stable/configuration.html for the
92
- full list of acceptable parameters. A commented list of all
93
- configuration options can also be generated by running puppet debugger with
94
- '--genconfig'.
100
+ * --help:
101
+ Print this help message
95
102
 
96
- * --help:
97
- Print this help message
103
+ * --version:
104
+ Print the puppet version number and exit.
98
105
 
99
- * --version:
100
- Print the puppet version number and exit.
106
+ * --execute:
107
+ Execute a specific piece of Puppet code
101
108
 
102
- * --execute:
103
- Execute a specific piece of Puppet code
109
+ * --facterdb-filter
110
+ Disables the usage of the current node level facts and uses cached facts
111
+ from facterdb. Specifying a filter will override the default facterdb filter.
112
+ Not specifiying a filter will use the default CentOS based filter.
113
+ This will greatly speed up the start time of the debugger since
114
+ you are using cached facts. Additionally, using facterdb also allows you
115
+ to play with many other operating system facts that you might not have access
116
+ to. For example filters please see the facterdb docs.
104
117
 
105
- * --facterdb-filter
106
- Disables the usage of the current node level facts and uses cached facts
107
- from facterdb. Specifying a filter will override the default facterdb filter.
108
- Not specifiying a filter will use the default CentOS based filter.
109
- This will greatly speed up the start time of the debugger since
110
- you are using cached facts. Additionally, using facterdb also allows you
111
- to play with many other operating system facts that you might not have access
112
- to. For example filters please see the facterdb docs.
118
+ See https://github.com/camptocamp/facterdb for more info
113
119
 
114
- See https://github.com/camptocamp/facterdb for more info
120
+ * --no-facterdb
121
+ Use the facts found on this node instead of cached facts from facterdb.
115
122
 
116
- * --no-facterdb
117
- Use the facts found on this node instead of cached facts from facterdb.
123
+ * --log-level
124
+ Set the Puppet log level which can be very useful with using the debugger.
118
125
 
119
- * --log-level
120
- Set the Puppet log level which can be very useful with using the debugger.
126
+ * --quiet
127
+ Do not display the debugger help script upon startup.
121
128
 
122
- * --quiet
123
- Do not display the debugger help script upon startup.
129
+ * --play
130
+ Plays back the code file supplied into the debugger. Can also supply
131
+ any http based url.
124
132
 
125
- * --play
126
- Plays back the code file supplied into the debugger. Can also supply
127
- any http based url.
133
+ * --run-once
134
+ Return the result from the debugger and exit
128
135
 
129
- * --run-once
130
- Return the result from the debugger and exit
136
+ * --stdin
137
+ Read from stdin instead of starting the debugger right away. Useful when piping code into the debugger.
131
138
 
132
- * --stdin
133
- Read from stdin instead of starting the debugger right away. Useful when piping code into the debugger.
139
+ * --catalog:
140
+ Import a JSON catalog (such as one generated with 'puppet master --compile'). You need to
141
+ specify a valid JSON encoded catalog file. Gives you the ability
142
+ to inspect the catalog and all the parameter values that make up the resources. Can
143
+ specify a file or pipe to stdin with '-'.
134
144
 
135
- * --node-name
136
- Retrieves the node information remotely via the puppet server given the node name.
137
- This is extremely useful when trying to debug classification issues, as this can show
138
- classes and parameters retrieved from the ENC. You can also play around with the real facts
139
- of the remote node as well.
145
+ * --node-name
146
+ Retrieves the node information remotely via the puppet server given the node name.
147
+ This is extremely useful when trying to debug classification issues, as this can show
148
+ classes and parameters retrieved from the ENC. You can also play around with the real facts
149
+ of the remote node as well.
140
150
 
141
- Note: this requires special permission in your puppet server's auth.conf file to allow
142
- access to make remote calls from this node: #{Puppet[:certname]}
151
+ Note: this requires special permission in your puppet server's auth.conf file to allow
152
+ access to make remote calls from this node: #{Puppet[:certname]}. If you are running
153
+ the debugger from the puppet server as root you do not need any special setup.
143
154
 
144
- You must also have a signed cert and be able to connect to the server from this system.
155
+ You must also have a signed cert and be able to connect to the server from this system.
145
156
 
146
- Mutually exclusive with --facterdb-filter
157
+ Mutually exclusive with --facterdb-filter
147
158
 
148
- * --test
149
- Runs the code in the debugger and exit without showing the help screen ( --quiet --run-once, --stdin)
159
+ * --test
160
+ Runs the code in the debugger and exit without showing the help screen ( --quiet --run-once, --stdin)
150
161
 
151
- EXAMPLE
152
- -------
153
- $ puppet debugger
154
- $ echo "notice('hello, can you hear me?')" | puppet debugger --test
155
- $ echo "notice('hello, can you hear me?')" | puppet debugger --stdin
156
- $ puppet debugger --execute "notice('hello')"
157
- $ puppet debugger --facterdb-filter 'facterversion=/^2.4\./ and operatingsystem=Debian'
158
- $ puppet debugger --play https://gist.github.com/logicminds/4f6bcfd723c92aad1f01f6a800319fa4
159
- $ puppet debugger --facterdb-filter 'facterversion=/^2.4\./ and operatingsystem=Debian' \\
160
- --play https://gist.github.com/logicminds/4f6bcfd723c92aad1f01f6a800319fa4
161
- $ puppet debugger --node-name
162
+ EXAMPLE
163
+ -------
164
+ $ puppet debugger
165
+ $ echo "notice('hello, can you hear me?')" | puppet debugger --test
166
+ $ echo "notice('hello, can you hear me?')" | puppet debugger --stdin
167
+ $ puppet debugger --execute "notice('hello')"
168
+ $ puppet debugger --facterdb-filter 'facterversion=/^2.4\./ and operatingsystem=Debian'
169
+ $ puppet debugger --play https://gist.github.com/logicminds/4f6bcfd723c92aad1f01f6a800319fa4
170
+ $ puppet debugger --facterdb-filter 'facterversion=/^2.4\./ and operatingsystem=Debian' \\
171
+ --play https://gist.github.com/logicminds/4f6bcfd723c92aad1f01f6a800319fa4
172
+ $ puppet debugger --node-name
162
173
 
163
174
 
164
- AUTHOR
165
- ------
166
- Corey Osman <corey@nwops.io>
175
+ AUTHOR
176
+ ------
177
+ Corey Osman <corey@nwops.io>
167
178
 
168
179
 
169
- COPYRIGHT
170
- ---------
171
- Copyright (c) 2019 NWOps
180
+ COPYRIGHT
181
+ ---------
182
+ Copyright (c) 2019 NWOps
172
183
 
173
184
  HELP
174
185
  end
175
186
 
176
187
  def initialize(command_line = Puppet::Util::CommandLine.new)
177
188
  @command_line = CommandLineArgs.new(command_line.subcommand_name, command_line.args.dup)
178
- @options = { use_facterdb: true, play: nil, run_once: false, node_name: nil, quiet: false, help: false, scope: nil }
189
+ @options = { use_facterdb: true, play: nil, run_once: false,
190
+ node_name: nil, quiet: false, help: false, scope: nil,
191
+ catalog: nil }
179
192
  @use_stdin = false
180
193
  begin
181
- require "puppet-debugger"
182
- rescue LoadError => e
183
- Puppet.err("You must install the puppet-debugger: gem install puppet-debugger")
194
+ require 'puppet-debugger'
195
+ rescue LoadError
196
+ Puppet.err('You must install the puppet-debugger: gem install puppet-debugger')
184
197
  end
185
198
  end
186
199
 
@@ -188,26 +201,26 @@ Copyright (c) 2019 NWOps
188
201
  # if this is a file we don't play back since its part of the environment
189
202
  # if just the code we put in a file and use the play feature of the debugger
190
203
  # we could do the same thing with the passed in manifest file but that might be too much code to show
191
-
192
204
  if options[:code]
193
205
  code_input = options.delete(:code)
194
- file = Tempfile.new(["puppet_repl_input", ".pp"])
195
- File.open(file, "w") do |f|
206
+ file = Tempfile.new(['puppet_debugger_input', '.pp'])
207
+ File.open(file, 'w') do |f|
196
208
  f.write(code_input)
197
209
  end
198
210
  options[:play] = file
199
211
  elsif command_line.args.empty? && use_stdin
200
212
  code_input = STDIN.read
201
- file = Tempfile.new(["puppet_repl_input", ".pp"])
202
- File.open(file, "w") do |f|
213
+ file = Tempfile.new(['puppet_debugger_input', '.pp'])
214
+ File.open(file, 'w') do |f|
203
215
  f.write(code_input)
204
216
  end
205
217
  options[:play] = file
206
218
  elsif !command_line.args.empty?
207
219
  manifest = command_line.args.shift
208
220
  raise "Could not find file #{manifest}" unless Puppet::FileSystem.exist?(manifest)
209
- Puppet.warning("Only one file can be used per run. Skipping #{command_line.args.join(", ")}") unless command_line.args.empty?
210
- options[:play] = file
221
+
222
+ Puppet.warning("Only one file can be used per run. Skipping #{command_line.args.join(', ')}") unless command_line.args.empty?
223
+ options[:play] = manifest
211
224
  end
212
225
  begin
213
226
  if !options[:use_facterdb] && options[:node_name].nil?
@@ -220,16 +233,23 @@ Copyright (c) 2019 NWOps
220
233
  end
221
234
  ::PuppetDebugger::Cli.start_without_stdin(options)
222
235
  rescue Exception => e
223
- puts e
224
- exit 1
236
+ case e.class.to_s
237
+ when 'SystemExit'
238
+ nil
239
+ else
240
+ puts e.message
241
+ puts e.backtrace
242
+ end
225
243
  end
226
244
  end
227
245
 
228
246
  def create_environment(manifest)
229
247
  configured_environment = Puppet.lookup(:current_environment)
230
- manifest ?
231
- configured_environment.override_with(manifest: manifest) :
248
+ if manifest
249
+ configured_environment.override_with(manifest: manifest)
250
+ else
232
251
  configured_environment
252
+ end
233
253
  end
234
254
 
235
255
  def create_node(environment)
@@ -239,14 +259,16 @@ Copyright (c) 2019 NWOps
239
259
  unless facts = Puppet::Node::Facts.indirection.find(Puppet[:node_name_value])
240
260
  raise "Could not find facts for #{Puppet[:node_name_value]}"
241
261
  end
262
+
242
263
  Puppet[:node_name_value] = facts.values[Puppet[:node_name_fact]]
243
264
  facts.name = Puppet[:node_name_value]
244
265
  end
245
- Puppet.override({ current_environment: environment }, "For puppet debugger") do
266
+ Puppet.override({ current_environment: environment }, 'For puppet debugger') do
246
267
  # Find our Node
247
268
  unless node = Puppet::Node.indirection.find(Puppet[:node_name_value])
248
269
  raise "Could not find node #{Puppet[:node_name_value]}"
249
270
  end
271
+
250
272
  # Merge in the facts.
251
273
  node.merge(facts.values) if facts
252
274
  end
@@ -269,11 +291,14 @@ Copyright (c) 2019 NWOps
269
291
  if $stdout.isatty
270
292
  options = options.merge(scope: scope)
271
293
  # required in order to use convert puppet hash into ruby hash with symbols
272
- options = options.each_with_object({}) { |(k, v), data| data[k.to_sym] = v; data }
294
+ options = options.each_with_object({}) do |(k, v), data|
295
+ data[k.to_sym] = v
296
+ data
297
+ end
273
298
  # options[:source_file], options[:source_line] = stacktrace.last
274
299
  ::PuppetRepl::Cli.start(options)
275
300
  else
276
- Puppet.info "puppet debug: refusing to start the debugger without a tty"
301
+ Puppet.info 'puppet debug: refusing to start the debugger without a tty'
277
302
  end
278
303
  end
279
304
 
@@ -284,7 +309,7 @@ Copyright (c) 2019 NWOps
284
309
  # for compatibility with older puppet versions
285
310
  # The basics behind this are to find the `.pp` file in the list of loaded code
286
311
  def stacktrace
287
- result = caller.each_with_object([]) do |loc, memo|
312
+ caller.each_with_object([]) do |loc, memo|
288
313
  if loc =~ /\A(.*\.pp)?:([0-9]+):in\s(.*)/
289
314
  # if the file is not found we set to code
290
315
  # and read from Puppet[:code]