require 'puppet/face'
require 'puppet/parser'
Puppet::Face.define(:parser, '0.0.1') do
copyright "Puppet Inc.", 2014
license _("Apache 2 license; see COPYING")
summary _("Interact directly with the parser.")
action :validate do
summary _("Validate the syntax of one or more Puppet manifests.")
arguments _("[<manifest>] [<manifest> ...]")
returns _("Nothing, or the first syntax error encountered.")
description <<-'EOT'
This action validates Puppet DSL syntax without compiling a catalog or
syncing any resources. If no manifest files are provided, it will
validate the default site manifest.
When validating multiple issues per file are reported up
to the settings of max_error, and max_warnings. The processing stops
after having reported issues for the first encountered file with errors.
EOT
examples <<-'EOT'
Validate the default site manifest at /etc/puppetlabs/puppet/manifests/site.pp:
$ puppet parser validate
Validate two arbitrary manifest files:
$ puppet parser validate init.pp vhost.pp
Validate from STDIN:
$ cat init.pp | puppet parser validate
EOT
when_invoked do |*args|
files = args.slice(0..-2)
parse_errors = {}
if files.empty?
if not STDIN.tty?
Puppet[:code] = STDIN.read
error = validate_manifest(nil)
parse_errors['STDIN'] = error if error
else
manifest = Puppet.lookup(:current_environment).manifest
files << manifest
Puppet.notice _("No manifest specified. Validating the default manifest %{manifest}") % { manifest: manifest }
end
end
missing_files = []
files.each do |file|
if Puppet::FileSystem.exist?(file)
error = validate_manifest(file)
parse_errors[file] = error if error
else
missing_files << file
end
end
unless missing_files.empty?
raise Puppet::Error, _("One or more file(s) specified did not exist:\n%{files}") % { files: missing_files.collect {|f| " " * 3 + f + "\n"} }
end
parse_errors
end
when_rendering :console do |errors|
unless errors.empty?
errors.each { |_, error| Puppet.log_exception(error) }
exit(1)
end
# Prevent face_base renderer from outputting "null"
exit(0)
end
when_rendering :json do |errors|
unless errors.empty?
ignore_error_keys = [ :arguments, :environment, :node ]
data = errors.map do |file, error|
file_errors = error.to_h.reject { |k, _| ignore_error_keys.include?(k) }
[file, file_errors]
end.to_h
puts Puppet::Util::Json.dump(Puppet::Pops::Serialization::ToDataConverter.convert(data, rich_data: false, symbol_as_string: true), :pretty => true)
exit(1)
end
# Prevent face_base renderer from outputting "null"
exit(0)
end
end
action (:dump) do
summary _("Outputs a dump of the internal parse tree for debugging")
arguments "[--format <old|pn|json>] [--pretty] { -e <source> | [<templates> ...] } "
returns _("A dump of the resulting AST model unless there are syntax or validation errors.")
description <<-'EOT'
This action parses and validates the Puppet DSL syntax without compiling a catalog
or syncing any resources.
The output format can be controlled using the --format <old|pn|json> where:
* 'old' is the default, but now deprecated format which is not API.
* 'pn' is the Puppet Extended S-Expression Notation.
* 'json' outputs the same graph as 'pn' but with JSON syntax.
The output will be "pretty printed" when the option --pretty is given together with --format 'pn' or 'json'.
This option has no effect on the 'old' format.
The command accepts one or more manifests (.pp) files, or an -e followed by the puppet
source text.
If no arguments are given, the stdin is read (unless it is attached to a terminal)
The output format of the dumped tree is intended for debugging purposes and is
not API, it may change from time to time.
EOT
option "--e " + _("<source>") do
default_to { nil }
summary _("dump one source expression given on the command line.")
end
option("--[no-]validate") do
summary _("Whether or not to validate the parsed result, if no-validate only syntax errors are reported")
end
option('--format ' + _('<old, pn, or json>')) do
summary _("Get result in 'old' (deprecated format), 'pn' (new format), or 'json' (new format in JSON).")
end
option('--pretty') do
summary _('Pretty print output. Only applicable together with --format pn or json')
end
when_invoked do |*args|
require 'puppet/pops'
options = args.pop
if options[:e]
dump_parse(options[:e], 'command-line-string', options, false)
elsif args.empty?
if ! STDIN.tty?
dump_parse(STDIN.read, 'stdin', options, false)
else
raise Puppet::Error, _("No input to parse given on command line or stdin")
end
else
files = args
available_files = files.select do |file|
Puppet::FileSystem.exist?(file)
end
missing_files = files - available_files
dumps = available_files.collect do |file|
dump_parse(Puppet::FileSystem.read(file, :encoding => 'utf-8'), file, options)
end.join("")
if missing_files.empty?
dumps
else
dumps + _("One or more file(s) specified did not exist:\n") + missing_files.collect { |f| " #{f}" }.join("\n")
end
end
end
end
def dump_parse(source, filename, options, show_filename = true)
output = ""
evaluating_parser = Puppet::Pops::Parser::EvaluatingParser.new
begin
if options[:validate]
parse_result = evaluating_parser.parse_string(source, filename)
else
# side step the assert_and_report step
parse_result = evaluating_parser.parser.parse_string(source)
end
if show_filename
output << "--- #{filename}"
end
fmt = options[:format]
if fmt.nil? || fmt == 'old'
output << Puppet::Pops::Model::ModelTreeDumper.new.dump(parse_result) << "\n"
else
require 'puppet/pops/pn'
pn = Puppet::Pops::Model::PNTransformer.transform(parse_result)
case fmt
when 'json'
options[:pretty] ? JSON.pretty_unparse(pn.to_data) : JSON.dump(pn.to_data)
else
pn.format(options[:pretty] ? Puppet::Pops::PN::Indent.new(' ') : nil, output)
end
end
rescue Puppet::ParseError => detail
if show_filename
Puppet.err("--- #{filename}")
end
Puppet.err(detail.message)
""
end
end
# @api private
def validate_manifest(manifest = nil)
env = Puppet.lookup(:current_environment)
loaders = Puppet::Pops::Loaders.new(env)
Puppet.override( {:loaders => loaders } , _('For puppet parser validate')) do
begin
validation_environment = manifest ? env.override_with(:manifest => manifest) : env
validation_environment.check_for_reparse
validation_environment.known_resource_types.clear
rescue Puppet::ParseError => parse_error
return parse_error
end
end
nil
end
end
Copyright 2K16 - 2K18 Indonesian Hacker Rulez