Module: PuppetDebugger::Support

Includes:
Compilier, Environment, Facts, Loader, Node, Scope
Included in:
Cli
Defined in:
lib/puppet-debugger/support.rb,
lib/puppet-debugger/support/node.rb,
lib/puppet-debugger/support/facts.rb,
lib/puppet-debugger/support/scope.rb,
lib/puppet-debugger/support/loader.rb,
lib/puppet-debugger/support/compiler.rb,
lib/puppet-debugger/support/environment.rb

Defined Under Namespace

Modules: Compilier, Environment, Facts, Loader, Node, Scope

Instance Method Summary collapse

Methods included from Loader

#create_loader, #loaders

Methods included from Node

#convert_remote_node, #create_node, #create_real_node, #get_remote_node, #node, #remote_node_name, #remote_node_name=, #set_node, #set_node_from_name, #set_remote_node_name

Methods included from Scope

#catalog, #create_scope, #get_catalog_text, #scope, #scope_vars, #set_catalog, #set_scope

Methods included from Facts

#default_facter_version, #default_facterdb_filter, #default_facts, #dynamic_facterdb_filter, #facter_os_name, #facter_os_version, #facter_version, #node_facts, #server_facts, #set_facts

Methods included from Environment

#bolt_modules, #create_environment, #create_node_environment, #default_manifests_dir, #default_modules_paths, #default_puppet_env_name, #default_site_manifest, #environment_loaders, #modules_paths, #puppet_env_name, #puppet_environment, #set_environment

Methods included from Compilier

#compiler, #create_compiler, #set_compiler

Instance Method Details

#bolt_pdb_clientBolt::PuppetDB::Client

Returns:

  • (Bolt::PuppetDB::Client)


146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/puppet-debugger/support.rb', line 146

def bolt_pdb_client
  @bolt_pdb_client ||=
    begin
      require 'bolt/logger'
      require 'bolt/puppetdb'
      require 'bolt/puppetdb/client'
      require 'bolt/puppetdb/config'
      config = Bolt::PuppetDB::Config.load_config({})
      Bolt::PuppetDB::Client.new(config)
    rescue LoadError
      # not puppet 6+
      nil
    end
end

#do_initializeObject

this is required in order to load things only when we need them



99
100
101
102
103
104
105
106
# File 'lib/puppet-debugger/support.rb', line 99

def do_initialize
  Puppet.initialize_settings
  Puppet[:parser] = 'future' # this is required in order to work with puppet 3.8
  Puppet[:trusted_node_data] = true
rescue ArgumentError
rescue Puppet::DevError
  # do nothing otherwise calling init twice raises an error
end

#generate_ast(string = nil) ⇒ Object

Returns Hostclass - a puppet Program object which is considered the main class.

Parameters:

  • String
    • any valid puppet language code

Returns:

  • Hostclass - a puppet Program object which is considered the main class



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/puppet-debugger/support.rb', line 110

def generate_ast(string = nil)
  parse_result = parser.parse_string(string, '')
  # the parse_result may be
  # * empty / nil (no input)
  # * a Model::Program
  # * a Model::Expression
  #
  # should return nil or Puppet::Pops::Model::Program
  # puppet 5 does not have the method current
  model = parse_result.respond_to?(:current) ? parse_result.current : parse_result
  args = {}
  ::Puppet::Pops::Model::AstTransformer.new('').merge_location(args, model)

  ast_code =
    if model.is_a? ::Puppet::Pops::Model::Program
      ::Puppet::Parser::AST::PopsBridge::Program.new(model, args)
    else
      args[:value] = model
      ::Puppet::Parser::AST::PopsBridge::Expression.new(args)
    end
  # Create the "main" class for the content - this content will get merged with all other "main" content
  ::Puppet::Parser::AST::Hostclass.new('', code: ast_code)
end

#initialize_from_scope(value) ⇒ Object



70
71
72
73
74
75
76
77
# File 'lib/puppet-debugger/support.rb', line 70

def initialize_from_scope(value)
  set_scope(value)
  if value
    set_environment(value.environment)
    set_node(value.compiler.node) if defined?(value.compiler.node)
    set_compiler(value.compiler)
  end
end

#known_resource_typesObject



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/puppet-debugger/support.rb', line 79

def known_resource_types
  res = {
    hostclasses: scope.environment.known_resource_types.hostclasses.keys,
    definitions: scope.environment.known_resource_types.definitions.keys,
    nodes: scope.environment.known_resource_types.nodes.keys
  }
  if sites = scope.environment.known_resource_types.instance_variable_get(:@sites)
    res[:sites] = sites
  end
  if apps = scope.environment.known_resource_types.respond_to?(:applications)
    res[:applications] = apps
  end
  # some versions of puppet do not support capabilities
  if maps = scope.environment.known_resource_types.respond_to?(:capability_mappings)
    res[:capability_mappings] = maps
  end
  res
end

#lib_dirs(module_dirs = modules_paths) ⇒ Object



46
47
48
49
50
51
# File 'lib/puppet-debugger/support.rb', line 46

def lib_dirs(module_dirs = modules_paths)
  dirs = module_dirs.map do |mod_dir|
    Dir["#{mod_dir}/*/lib"].entries
  end.flatten
  dirs + [puppet_debugger_lib_dir]
end

#manifest_file(input) ⇒ String

Returns the path to the manifest file.

Parameters:

  • input (String)

    the manfiest content

Returns:

  • (String)

    the path to the manifest file



137
138
139
140
141
142
143
# File 'lib/puppet-debugger/support.rb', line 137

def manifest_file(input)
  file = Tempfile.new(['puppet_debugger_input', '.pp'])
  File.open(file, 'w') do |f|
    f.write(input)
  end
  file
end

#mod_finderObject

returns either the module name or puppet version



58
59
60
# File 'lib/puppet-debugger/support.rb', line 58

def mod_finder
  @mod_finder ||= Regexp.new('\/([\w\-\.]+)\/lib')
end

#parse_error(error) ⇒ Object

parses the error type into a more useful error message defined in errors.rb returns new error object or the original if error cannot be parsed



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/puppet-debugger/support.rb', line 23

def parse_error(error)
  case error
  when SocketError
    PuppetDebugger::Exception::ConnectError.new(message: "Unknown host: #{Puppet[:server]}")
  when Net::HTTPError
    PuppetDebugger::Exception::AuthError.new(message: error.message)
  when Errno::ECONNREFUSED
    PuppetDebugger::Exception::ConnectError.new(message: error.message)
  when Puppet::Error
    if error.message =~ /could\ not\ find\ class/i
      PuppetDebugger::Exception::NoClassError.new(default_modules_paths: default_modules_paths,
                                                  message: error.message)
    elsif error.message =~ /default\ node/i
      PuppetDebugger::Exception::NodeDefinitionError.new(default_site_manifest: default_site_manifest,
                                                         message: error.message)
    else
      error
    end
  else
    error
  end
end

#parserObject

returns a future parser for evaluating code



200
201
202
# File 'lib/puppet-debugger/support.rb', line 200

def parser
  @parser ||= ::Puppet::Pops::Parser::EvaluatingParser.new
end

#puppet_debugger_lib_dirObject

Deprecated.

this is the lib directory of this gem in order to load any puppet functions from this gem we need to add the lib path of this gem



66
67
68
# File 'lib/puppet-debugger/support.rb', line 66

def puppet_debugger_lib_dir
  File.expand_path(File.join(File.dirname(File.dirname(File.dirname(__FILE__))), 'lib'))
end

#puppet_eval(input, file: nil) ⇒ Object

Returns Object - returns either a string of the result or object from puppet evaulation.

Parameters:

  • String
    • any valid puppet language code

Returns:

  • Object - returns either a string of the result or object from puppet evaulation



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/puppet-debugger/support.rb', line 163

def puppet_eval(input, file: nil)
  # in order to add functions to the scope the loaders must be created
  # in order to call native functions we need to set the global_scope
  # record the input for puppet to retrieve and reference later
  manifest_file = file || manifest_file(input)
  manfifest_content = input || File.read(manifest_file)
  ast = generate_ast(manfifest_content)
  Puppet.override({ current_environment: puppet_environment, manifest: manifest_file,
                    global_scope: scope, bolt_pdb_client: bolt_pdb_client,
                    loaders: scope.compiler.loaders }, 'For puppet-debugger') do
    # because the debugger is not a module we leave the modname blank
    scope.environment.known_resource_types.import_ast(ast, '')

    exec_hook :before_eval, '', self, self
    if bench
      result = nil
      time = Benchmark.realtime do
        result = parser.evaluate_string(scope, manfifest_content, File.expand_path(manifest_file))
      end
      out = [result, "Time elapsed #{(time * 1000).round(2)} ms"]
    else
      out = parser.evaluate_string(scope, manfifest_content, File.expand_path(manifest_file))
    end
    exec_hook :after_eval, out, self, self
    out
  end
end

#puppet_lib_dirObject



191
192
193
194
195
196
197
# File 'lib/puppet-debugger/support.rb', line 191

def puppet_lib_dir
  # returns something like "/Library/Ruby/Gems/2.0.0/gems/puppet-4.2.2/lib/puppet.rb"
  # "/Users/adam/.rbenv/versions/2.2.6/lib/ruby/gems/2.2.0/gems/puppet-4.9.4/lib"

  # this is only useful when returning a namespace with the functions
  @puppet_lib_dir ||= File.dirname(Puppet.method(:[]).source_location.first)
end

#static_responder_listObject



53
54
55
# File 'lib/puppet-debugger/support.rb', line 53

def static_responder_list
  PuppetDebugger::InputResponders::Commands.command_list
end