puppet-debugger 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +54 -0
- data/.gitlab-ci.yml +129 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +61 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +67 -0
- data/LICENSE.txt +20 -0
- data/README.md +276 -0
- data/Rakefile +32 -0
- data/bin/pdb +4 -0
- data/lib/awesome_print/ext/awesome_puppet.rb +40 -0
- data/lib/puppet-debugger/cli.rb +247 -0
- data/lib/puppet-debugger/code/code_file.rb +98 -0
- data/lib/puppet-debugger/code/code_range.rb +69 -0
- data/lib/puppet-debugger/code/loc.rb +80 -0
- data/lib/puppet-debugger/debugger_code.rb +318 -0
- data/lib/puppet-debugger/support/compiler.rb +20 -0
- data/lib/puppet-debugger/support/environment.rb +38 -0
- data/lib/puppet-debugger/support/errors.rb +75 -0
- data/lib/puppet-debugger/support/facts.rb +78 -0
- data/lib/puppet-debugger/support/functions.rb +72 -0
- data/lib/puppet-debugger/support/input_responders.rb +136 -0
- data/lib/puppet-debugger/support/node.rb +90 -0
- data/lib/puppet-debugger/support/play.rb +91 -0
- data/lib/puppet-debugger/support/scope.rb +42 -0
- data/lib/puppet-debugger/support.rb +176 -0
- data/lib/puppet-debugger.rb +55 -0
- data/lib/trollop.rb +861 -0
- data/lib/version.rb +3 -0
- data/puppet-debugger.gemspec +36 -0
- data/run_container_test.sh +12 -0
- data/spec/facts_spec.rb +86 -0
- data/spec/fixtures/environments/production/manifests/site.pp +1 -0
- data/spec/fixtures/invalid_node_obj.yaml +8 -0
- data/spec/fixtures/node_obj.yaml +298 -0
- data/spec/fixtures/sample_manifest.pp +2 -0
- data/spec/fixtures/sample_start_debugger.pp +13 -0
- data/spec/pdb_spec.rb +50 -0
- data/spec/puppet-debugger_spec.rb +492 -0
- data/spec/remote_node_spec.rb +170 -0
- data/spec/spec_helper.rb +57 -0
- data/spec/support_spec.rb +190 -0
- data/test_matrix.rb +42 -0
- metadata +148 -0
@@ -0,0 +1,136 @@
|
|
1
|
+
module PuppetDebugger
|
2
|
+
module Support
|
3
|
+
module InputResponders
|
4
|
+
|
5
|
+
def static_responder_list
|
6
|
+
["exit", "functions", "classification","vars", 'facterdb_filter', "krt", "facts",
|
7
|
+
"resources", "classes", "whereami", "play","reset", "help"
|
8
|
+
]
|
9
|
+
end
|
10
|
+
|
11
|
+
# @source_file and @source_line_num instance variables must be set for this
|
12
|
+
# method to show the surrounding code
|
13
|
+
# @return [String] - string output of the code surrounded by the breakpoint or nil if file or line_num do not exist
|
14
|
+
def whereami(command=nil, args=nil)
|
15
|
+
file=@source_file
|
16
|
+
line_num=@source_line_num
|
17
|
+
if file and line_num
|
18
|
+
if file == :code
|
19
|
+
source_code = Puppet[:code]
|
20
|
+
code = DebuggerCode.from_string(source_code, :puppet)
|
21
|
+
else
|
22
|
+
code = DebuggerCode.from_file(file, :puppet)
|
23
|
+
end
|
24
|
+
return code.with_marker(line_num).around(line_num, 5).with_line_numbers.with_indentation(5).to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# displays the facterdb filter
|
29
|
+
# @param [Array] - args is not used
|
30
|
+
def facterdb_filter(args=[])
|
31
|
+
dynamic_facterdb_filter.ai
|
32
|
+
end
|
33
|
+
|
34
|
+
def help(args=[])
|
35
|
+
PuppetDebugger::Cli.print_repl_desc
|
36
|
+
end
|
37
|
+
|
38
|
+
def handle_set(input)
|
39
|
+
output = ''
|
40
|
+
args = input.split(' ')
|
41
|
+
args.shift # throw away the set
|
42
|
+
case args.shift
|
43
|
+
when /node/
|
44
|
+
if name = args.shift
|
45
|
+
output = "Resetting to use node #{name}"
|
46
|
+
reset
|
47
|
+
set_remote_node_name(name)
|
48
|
+
else
|
49
|
+
out_buffer.puts "Must supply a valid node name"
|
50
|
+
end
|
51
|
+
when /loglevel/
|
52
|
+
if level = args.shift
|
53
|
+
@log_level = level
|
54
|
+
set_log_level(level)
|
55
|
+
output = "loglevel #{Puppet::Util::Log.level} is set"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
output
|
59
|
+
end
|
60
|
+
|
61
|
+
def facts(args=[])
|
62
|
+
variables = node.facts.values
|
63
|
+
variables.ai({:sort_keys => true, :indent => -1})
|
64
|
+
end
|
65
|
+
|
66
|
+
def functions(args=[])
|
67
|
+
filter = args.first || ''
|
68
|
+
function_map.keys.sort.grep(/^#{Regexp.escape(filter)}/)
|
69
|
+
end
|
70
|
+
|
71
|
+
def vars(args=[])
|
72
|
+
# remove duplicate variables that are also in the facts hash
|
73
|
+
variables = scope.to_hash.delete_if {| key, value | node.facts.values.key?(key) }
|
74
|
+
variables['facts'] = 'removed by the puppet-debugger' if variables.key?('facts')
|
75
|
+
output = "Facts were removed for easier viewing".ai + "\n"
|
76
|
+
output += variables.ai({:sort_keys => true, :indent => -1})
|
77
|
+
end
|
78
|
+
|
79
|
+
def environment(args=[])
|
80
|
+
"Puppet Environment: #{puppet_env_name}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def reset(args=[])
|
84
|
+
set_scope(nil)
|
85
|
+
set_remote_node_name(nil)
|
86
|
+
set_node(nil)
|
87
|
+
set_facts(nil)
|
88
|
+
set_environment(nil)
|
89
|
+
set_log_level(log_level)
|
90
|
+
end
|
91
|
+
|
92
|
+
def set_log_level(level)
|
93
|
+
Puppet::Util::Log.level = level.to_sym
|
94
|
+
buffer_log = Puppet::Util::Log.newdestination(:buffer)
|
95
|
+
if buffer_log
|
96
|
+
# if this is already set the buffer_log is nil
|
97
|
+
buffer_log.out_buffer = out_buffer
|
98
|
+
buffer_log.err_buffer = out_buffer
|
99
|
+
end
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
|
103
|
+
def krt(args=[])
|
104
|
+
known_resource_types.ai({:sort_keys => true, :indent => -1})
|
105
|
+
end
|
106
|
+
|
107
|
+
def play(args=[])
|
108
|
+
config = {}
|
109
|
+
config[:play] = args.first
|
110
|
+
play_back(config)
|
111
|
+
return nil # we don't want to return anything
|
112
|
+
end
|
113
|
+
|
114
|
+
def classification(args=[])
|
115
|
+
node.classes.ai
|
116
|
+
end
|
117
|
+
|
118
|
+
def resources(args=[])
|
119
|
+
res = scope.compiler.catalog.resources.map do |res|
|
120
|
+
res.to_s.gsub(/\[/, "['").gsub(/\]/, "']") # ensure the title has quotes
|
121
|
+
end
|
122
|
+
if !args.first.nil?
|
123
|
+
res[args.first.to_i].ai
|
124
|
+
else
|
125
|
+
output = "Resources not shown in any specific order\n".warning
|
126
|
+
output += res.ai
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def classes(args=[])
|
131
|
+
scope.compiler.catalog.classes.ai
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'puppet/indirector/node/rest'
|
2
|
+
|
3
|
+
module PuppetDebugger
|
4
|
+
module Support
|
5
|
+
module Node
|
6
|
+
# creates a node object using defaults or gets the remote node
|
7
|
+
# object if the remote_node_name is defined
|
8
|
+
def create_node
|
9
|
+
Puppet[:trusted_server_facts] = true if Puppet.version.to_f >= 4.1
|
10
|
+
|
11
|
+
if remote_node_name
|
12
|
+
# refetch
|
13
|
+
node_obj = set_node_from_name(remote_node_name)
|
14
|
+
end
|
15
|
+
unless node_obj
|
16
|
+
options = {}
|
17
|
+
options[:parameters] = default_facts.values
|
18
|
+
options[:facts] = default_facts
|
19
|
+
options[:classes] = []
|
20
|
+
options[:environment] = puppet_environment
|
21
|
+
name = default_facts.values['fqdn']
|
22
|
+
node_obj = Puppet::Node.new(name, options)
|
23
|
+
node_obj.add_server_facts(server_facts) if node_obj.respond_to?(:add_server_facts)
|
24
|
+
node_obj
|
25
|
+
end
|
26
|
+
node_obj
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_remote_node_name(name)
|
30
|
+
@remote_node_name = name
|
31
|
+
end
|
32
|
+
|
33
|
+
def remote_node_name=(name)
|
34
|
+
@remote_node_name = name
|
35
|
+
end
|
36
|
+
|
37
|
+
def remote_node_name
|
38
|
+
@remote_node_name
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [node] puppet node object
|
42
|
+
def node
|
43
|
+
@node ||= create_node
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_remote_node(name)
|
47
|
+
indirection = Puppet::Indirector::Indirection.instance(:node)
|
48
|
+
indirection.terminus_class = 'rest'
|
49
|
+
remote_node = indirection.find(name, :environment => puppet_environment)
|
50
|
+
remote_node
|
51
|
+
end
|
52
|
+
|
53
|
+
# this is a hack to get around that the puppet node fact face does not return
|
54
|
+
# a proper node object with the facts hash populated
|
55
|
+
# returns a node object with a proper facts hash
|
56
|
+
def convert_remote_node(remote_node)
|
57
|
+
options = {}
|
58
|
+
# remove trusted data as it will later get populated during compilation
|
59
|
+
parameters = remote_node.parameters.dup
|
60
|
+
trusted_data = parameters.delete('trusted')
|
61
|
+
options[:parameters] = parameters || {}
|
62
|
+
options[:facts] = Puppet::Node::Facts.new(remote_node.name,remote_node.parameters)
|
63
|
+
options[:classes] = remote_node.classes
|
64
|
+
options[:environment] = puppet_environment
|
65
|
+
node_object = Puppet::Node.new(remote_node.name, options)
|
66
|
+
node_object.add_server_facts(server_facts) if node_object.respond_to?(:add_server_facts)
|
67
|
+
node_object.trusted_data = trusted_data
|
68
|
+
node_object
|
69
|
+
end
|
70
|
+
|
71
|
+
# query the remote puppet server and retrieve the node object
|
72
|
+
#
|
73
|
+
def set_node_from_name(name)
|
74
|
+
out_buffer.puts ("Fetching node #{name}")
|
75
|
+
remote_node = get_remote_node(name)
|
76
|
+
if remote_node and remote_node.parameters.empty?
|
77
|
+
remote_node_name = nil # clear out the remote name
|
78
|
+
raise PuppetDebugger::Exception::UndefinedNode.new(:name => remote_node.name)
|
79
|
+
end
|
80
|
+
remote_node_name = remote_node.name
|
81
|
+
node_object = convert_remote_node(remote_node)
|
82
|
+
set_node(node_object)
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_node(value)
|
86
|
+
@node = value
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module PuppetDebugger
|
2
|
+
module Support
|
3
|
+
module Play
|
4
|
+
|
5
|
+
def play_back(config={})
|
6
|
+
if config[:play]
|
7
|
+
if config[:play] =~ /^http/
|
8
|
+
play_back_url(config[:play])
|
9
|
+
elsif File.exists? config[:play]
|
10
|
+
play_back_string(File.read(config[:play]))
|
11
|
+
else config[:play]
|
12
|
+
out_buffer.puts "puppet-debugger can't play #{config[:play]}'"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def convert_to_text(url)
|
18
|
+
require 'uri'
|
19
|
+
url_data = URI(url)
|
20
|
+
case url_data.host
|
21
|
+
when /^gist\.github*/
|
22
|
+
unless url_data.path =~ /raw/
|
23
|
+
url = url += '.txt'
|
24
|
+
end
|
25
|
+
url
|
26
|
+
when /^github.com/
|
27
|
+
if url_data.path =~ /blob/
|
28
|
+
url.gsub('blob', 'raw')
|
29
|
+
end
|
30
|
+
when /^gist.github.com/
|
31
|
+
unless url_data.path =~ /raw/
|
32
|
+
url = url += '.txt'
|
33
|
+
end
|
34
|
+
url
|
35
|
+
when /^gitlab.com/
|
36
|
+
if url_data.path =~ /snippets/
|
37
|
+
url += '/raw' unless url_data.path =~ /raw/
|
38
|
+
url
|
39
|
+
else
|
40
|
+
url.gsub('blob', 'raw')
|
41
|
+
end
|
42
|
+
else
|
43
|
+
url
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# opens the url and reads the data
|
48
|
+
def fetch_url_data(url)
|
49
|
+
open(url).read
|
50
|
+
end
|
51
|
+
|
52
|
+
def play_back_url(url)
|
53
|
+
begin
|
54
|
+
require 'open-uri'
|
55
|
+
require 'net/http'
|
56
|
+
converted_url = convert_to_text(url)
|
57
|
+
str = fetch_url_data(converted_url)
|
58
|
+
play_back_string(str)
|
59
|
+
rescue SocketError
|
60
|
+
abort "puppet-debugger can't play `#{converted_url}'"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# plays back the string to the output stream
|
65
|
+
# puts the input to the output as well as the produced output
|
66
|
+
def play_back_string(str)
|
67
|
+
full_buffer = ''
|
68
|
+
str.split("\n").each do |buf|
|
69
|
+
begin
|
70
|
+
full_buffer += buf
|
71
|
+
# unless this is puppet code, otherwise skip repl keywords
|
72
|
+
if keyword_expression.match(buf)
|
73
|
+
out_buffer.write(">> ")
|
74
|
+
else
|
75
|
+
parser.parse_string(full_buffer)
|
76
|
+
out_buffer.write(">> ")
|
77
|
+
end
|
78
|
+
rescue Puppet::ParseErrorWithIssue => e
|
79
|
+
if multiline_input?(e)
|
80
|
+
full_buffer += "\n"
|
81
|
+
next
|
82
|
+
end
|
83
|
+
end
|
84
|
+
out_buffer.puts(full_buffer)
|
85
|
+
handle_input(full_buffer)
|
86
|
+
full_buffer = ''
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module PuppetDebugger
|
2
|
+
module Support
|
3
|
+
module Scope
|
4
|
+
def set_scope(value)
|
5
|
+
@scope = value
|
6
|
+
end
|
7
|
+
|
8
|
+
# @return [Scope] puppet scope object
|
9
|
+
def scope
|
10
|
+
unless @scope
|
11
|
+
@scope ||= create_scope
|
12
|
+
end
|
13
|
+
@scope
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_scope
|
17
|
+
do_initialize
|
18
|
+
begin
|
19
|
+
@compiler = create_compiler(node) # creates a new compiler for each scope
|
20
|
+
scope = Puppet::Parser::Scope.new(@compiler)
|
21
|
+
# creates a node class
|
22
|
+
scope.source = Puppet::Resource::Type.new(:node, node.name)
|
23
|
+
scope.parent = @compiler.topscope
|
24
|
+
load_lib_dirs
|
25
|
+
# compiling will load all the facts into the scope
|
26
|
+
# without this step facts will not get resolved
|
27
|
+
scope.compiler.compile # this will load everything into the scope
|
28
|
+
rescue StandardError => e
|
29
|
+
err = parse_error(e)
|
30
|
+
raise err
|
31
|
+
end
|
32
|
+
scope
|
33
|
+
end
|
34
|
+
|
35
|
+
# returns a hash of varaibles that are currently in scope
|
36
|
+
def scope_vars
|
37
|
+
vars = scope.to_hash.delete_if {| key, value | node.facts.values.key?(key.to_sym) }
|
38
|
+
vars['facts'] = 'removed by the puppet-debugger'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'puppet/pops'
|
2
|
+
require 'facterdb'
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
# load all the generators found in the generators directory
|
6
|
+
Dir.glob(File.join(File.dirname(__FILE__),'support', '*.rb')).each do |file|
|
7
|
+
require_relative File.join('support', File.basename(file, '.rb'))
|
8
|
+
end
|
9
|
+
|
10
|
+
module PuppetDebugger
|
11
|
+
module Support
|
12
|
+
include PuppetDebugger::Support::Compilier
|
13
|
+
include PuppetDebugger::Support::Environment
|
14
|
+
include PuppetDebugger::Support::Facts
|
15
|
+
include PuppetDebugger::Support::Scope
|
16
|
+
include PuppetDebugger::Support::Functions
|
17
|
+
include PuppetDebugger::Support::Node
|
18
|
+
include PuppetDebugger::Support::InputResponders
|
19
|
+
include PuppetDebugger::Support::Play
|
20
|
+
|
21
|
+
# parses the error type into a more useful error message defined in errors.rb
|
22
|
+
# returns new error object or the original if error cannot be parsed
|
23
|
+
def parse_error(error)
|
24
|
+
case error
|
25
|
+
when SocketError
|
26
|
+
PuppetDebugger::Exception::ConnectError.new(:message => "Unknown host: #{Puppet[:server]}")
|
27
|
+
when Net::HTTPError
|
28
|
+
PuppetDebugger::Exception::AuthError.new(:message => error.message)
|
29
|
+
when Errno::ECONNREFUSED
|
30
|
+
PuppetDebugger::Exception::ConnectError.new(:message => error.message)
|
31
|
+
when Puppet::Error
|
32
|
+
if error.message =~ /could\ not\ find\ class/i
|
33
|
+
PuppetDebugger::Exception::NoClassError.new(:default_modules_paths => default_modules_paths,
|
34
|
+
:message => error.message)
|
35
|
+
elsif error.message =~ /default\ node/i
|
36
|
+
PuppetDebugger::Exception::NodeDefinitionError.new(:default_site_manifest => default_site_manifest,
|
37
|
+
:message => error.message)
|
38
|
+
else
|
39
|
+
error
|
40
|
+
end
|
41
|
+
else
|
42
|
+
error
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# returns an array of module directories, generally this is the only place
|
47
|
+
# to look for puppet code by default. This is read from the puppet configuration
|
48
|
+
def default_modules_paths
|
49
|
+
dirs = []
|
50
|
+
do_initialize if Puppet[:codedir].nil?
|
51
|
+
# add the puppet-debugger directory so we can load any defined functions
|
52
|
+
dirs << File.join(Puppet[:environmentpath],default_puppet_env_name,'modules') unless Puppet[:environmentpath].empty?
|
53
|
+
dirs << Puppet.settings[:basemodulepath].split(':')
|
54
|
+
dirs.flatten
|
55
|
+
end
|
56
|
+
|
57
|
+
# this is the lib directory of this gem
|
58
|
+
# in order to load any puppet functions from this gem we need to add the lib path
|
59
|
+
# of this gem
|
60
|
+
def puppet_repl_lib_dir
|
61
|
+
File.expand_path(File.join(File.dirname(File.dirname(File.dirname(__FILE__))), 'lib'))
|
62
|
+
end
|
63
|
+
|
64
|
+
# returns all the modules paths defined in the environment
|
65
|
+
def modules_paths
|
66
|
+
puppet_environment.full_modulepath
|
67
|
+
end
|
68
|
+
|
69
|
+
def initialize_from_scope(value)
|
70
|
+
set_scope(value)
|
71
|
+
unless value.nil?
|
72
|
+
set_environment(value.environment)
|
73
|
+
set_node(value.compiler.node)
|
74
|
+
set_compiler(value.compiler)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def keyword_expression
|
79
|
+
@keyword_expression ||= Regexp.new(/^exit|^:set|^play|^classification|^facts|^vars|^functions|^classes|^resources|^krt|^environment|^reset|^help/)
|
80
|
+
end
|
81
|
+
|
82
|
+
def known_resource_types
|
83
|
+
res = {
|
84
|
+
:hostclasses => scope.environment.known_resource_types.hostclasses.keys,
|
85
|
+
:definitions => scope.environment.known_resource_types.definitions.keys,
|
86
|
+
:nodes => scope.environment.known_resource_types.nodes.keys,
|
87
|
+
}
|
88
|
+
if sites = scope.environment.known_resource_types.instance_variable_get(:@sites)
|
89
|
+
res.merge!(:sites => scope.environment.known_resource_types.instance_variable_get(:@sites).first)
|
90
|
+
end
|
91
|
+
if scope.environment.known_resource_types.respond_to?(:applications)
|
92
|
+
res.merge!(:applications => scope.environment.known_resource_types.applications.keys)
|
93
|
+
end
|
94
|
+
# some versions of puppet do not support capabilities
|
95
|
+
if scope.environment.known_resource_types.respond_to?(:capability_mappings)
|
96
|
+
res.merge!(:capability_mappings => scope.environment.known_resource_types.capability_mappings.keys)
|
97
|
+
end
|
98
|
+
res
|
99
|
+
end
|
100
|
+
|
101
|
+
# this is required in order to load things only when we need them
|
102
|
+
def do_initialize
|
103
|
+
begin
|
104
|
+
Puppet.initialize_settings
|
105
|
+
Puppet[:parser] = 'future' # this is required in order to work with puppet 3.8
|
106
|
+
Puppet[:trusted_node_data] = true
|
107
|
+
rescue ArgumentError => e
|
108
|
+
|
109
|
+
rescue Puppet::DevError => e
|
110
|
+
# do nothing otherwise calling init twice raises an error
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# @param String - any valid puppet language code
|
115
|
+
# @return Hostclass - a puppet Program object which is considered the main class
|
116
|
+
def generate_ast(string = nil)
|
117
|
+
parse_result = parser.parse_string(string, '')
|
118
|
+
# the parse_result may be
|
119
|
+
# * empty / nil (no input)
|
120
|
+
# * a Model::Program
|
121
|
+
# * a Model::Expression
|
122
|
+
#
|
123
|
+
model = parse_result.nil? ? nil : parse_result.current
|
124
|
+
args = {}
|
125
|
+
::Puppet::Pops::Model::AstTransformer.new('').merge_location(args, model)
|
126
|
+
|
127
|
+
ast_code =
|
128
|
+
if model.is_a? ::Puppet::Pops::Model::Program
|
129
|
+
::Puppet::Parser::AST::PopsBridge::Program.new(model, args)
|
130
|
+
else
|
131
|
+
args[:value] = model
|
132
|
+
::Puppet::Parser::AST::PopsBridge::Expression.new(args)
|
133
|
+
end
|
134
|
+
# Create the "main" class for the content - this content will get merged with all other "main" content
|
135
|
+
::Puppet::Parser::AST::Hostclass.new('', :code => ast_code)
|
136
|
+
end
|
137
|
+
|
138
|
+
# @param String - any valid puppet language code
|
139
|
+
# @return Object - returns either a string of the result or object from puppet evaulation
|
140
|
+
def puppet_eval(input)
|
141
|
+
# in order to add functions to the scope the loaders must be created
|
142
|
+
# in order to call native functions we need to set the global_scope
|
143
|
+
ast = generate_ast(input)
|
144
|
+
# record the input for puppet to retrieve and reference later
|
145
|
+
file = Tempfile.new(['puppet_repl_input', '.pp'])
|
146
|
+
File.open(file, 'w') do |f|
|
147
|
+
f.write(input)
|
148
|
+
end
|
149
|
+
Puppet.override( {:code => input, :global_scope => scope, :loaders => scope.compiler.loaders } , 'For puppet-debugger') do
|
150
|
+
# because the repl is not a module we leave the modname blank
|
151
|
+
scope.environment.known_resource_types.import_ast(ast, '')
|
152
|
+
parser.evaluate_string(scope, input, File.expand_path(file))
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def puppet_lib_dir
|
157
|
+
# returns something like "/Library/Ruby/Gems/2.0.0/gems/puppet-4.2.2/lib/puppet.rb"
|
158
|
+
# this is only useful when returning a namespace with the functions
|
159
|
+
@puppet_lib_dir ||= File.dirname(Puppet.method(:[]).source_location.first)
|
160
|
+
end
|
161
|
+
|
162
|
+
# returns a future parser for evaluating code
|
163
|
+
def parser
|
164
|
+
@parser ||= ::Puppet::Pops::Parser::EvaluatingParser.new
|
165
|
+
end
|
166
|
+
|
167
|
+
def default_manifests_dir
|
168
|
+
File.join(Puppet[:environmentpath],default_puppet_env_name,'manifests')
|
169
|
+
end
|
170
|
+
|
171
|
+
def default_site_manifest
|
172
|
+
File.join(default_manifests_dir, 'site.pp')
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative 'puppet-debugger/cli'
|
2
|
+
require_relative 'version'
|
3
|
+
require 'awesome_print'
|
4
|
+
require_relative 'awesome_print/ext/awesome_puppet'
|
5
|
+
require_relative 'trollop'
|
6
|
+
require 'puppet/util/log'
|
7
|
+
require_relative 'puppet-debugger/debugger_code'
|
8
|
+
|
9
|
+
require_relative 'puppet-debugger/support/errors'
|
10
|
+
# monkey patch in some color effects string methods
|
11
|
+
class String
|
12
|
+
def red; "\033[31m#{self}\033[0m" end
|
13
|
+
def green; "\033[32m#{self}\033[0m" end
|
14
|
+
def cyan; "\033[36m#{self}\033[0m" end
|
15
|
+
def yellow; "\033[33m#{self}\033[0m" end
|
16
|
+
def warning; yellow end
|
17
|
+
def fatal; red end
|
18
|
+
def info; green end
|
19
|
+
|
20
|
+
def camel_case
|
21
|
+
return self if self !~ /_/ && self =~ /[A-Z]+.*/
|
22
|
+
split('_').map(&:capitalize).join
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Puppet::Util::Log.newdesttype :buffer do
|
27
|
+
require 'puppet/util/colors'
|
28
|
+
include Puppet::Util::Colors
|
29
|
+
|
30
|
+
attr_accessor :err_buffer, :out_buffer
|
31
|
+
|
32
|
+
def initialize(err=$stderr, out=$stdout)
|
33
|
+
@err_buffer = err
|
34
|
+
@out_buffer = out
|
35
|
+
end
|
36
|
+
|
37
|
+
def handle(msg)
|
38
|
+
levels = {
|
39
|
+
:emerg => { :name => 'Emergency', :color => :hred, :stream => err_buffer },
|
40
|
+
:alert => { :name => 'Alert', :color => :hred, :stream => err_buffer },
|
41
|
+
:crit => { :name => 'Critical', :color => :hred, :stream => err_buffer },
|
42
|
+
:err => { :name => 'Error', :color => :hred, :stream => err_buffer },
|
43
|
+
:warning => { :name => 'Warning', :color => :hred, :stream => err_buffer },
|
44
|
+
:notice => { :name => 'Notice', :color => :reset, :stream => out_buffer },
|
45
|
+
:info => { :name => 'Info', :color => :green, :stream => out_buffer },
|
46
|
+
:debug => { :name => 'Debug', :color => :cyan, :stream => out_buffer },
|
47
|
+
}
|
48
|
+
|
49
|
+
str = msg.respond_to?(:multiline) ? msg.multiline : msg.to_s
|
50
|
+
str = msg.source == "Puppet" ? str : "#{msg.source}: #{str}"
|
51
|
+
|
52
|
+
level = levels[msg.level]
|
53
|
+
level[:stream].puts colorize(level[:color], "#{level[:name]}: #{str}")
|
54
|
+
end
|
55
|
+
end
|