Device-Network-ConfigParser
view release on metacpan or search on metacpan
lib/Device/Network/ConfigParser.pm view on Meta::CPAN
Parsing modules exist within the C<Device::Network::ConfigParser::> namespace. For a I<vendor> and I<type> of device, the module is defined as C<Device::Network::ConfigParser::vendor::type>.
The harness takes care of parsing the command line arguments, opening files (or STDIN/STDOUT) and slurping in their contents. It calls specified subroutines exported by the specified parsing module. All modules must export the following subroutines:
=head2 get_parser
my $module_parser = get_parser();
This sub receives no arguments, and must return a reference to an object or subroutine that parses the configuration. This is most likely going to be a Parse::RecDescent object, but you're not limited to this.
=head2 parse_config
my $parsed_config = parse_config($module_parser, $device_config);
This sub receives the reference returned by the C<get_parser> sub, and the full contents of a file specified on the command line. It should return a reference a data structure that represents the parsed configuration.
=head2 post_process
my $processed_config = post_process($parsed_config);
This sub receives the reference to the data structure returned by C<parse_config>. It allows for some post-processing of the data structure. If no processing is required, it can be defined as C<sub post_process { return @_; }>.
=head2 get_output_drivers
open($fh, ">>:encoding(UTF-8)", $output_filename);
my $output_drivers = get_output_drivers();
$output_drivers->{csv}->($fh, $output_filename, $processed_config);
This sub takes no arguments, and must return a HASHREF of subroutines used to output the parsed configurationm keyed on the command line argument. For example the sub may return:
{
csv => \&csv_output_driver,
}
The drivers themselves take a filehandle to write the output to (this may be STDOUT), the output filename, and the post-processed configuration.
The driver called is based on the C<--output csv> as a command line argument
There are two default drivers:
=over 4
=item * the 'raw' driver, which uses Data::Dumper to serialise the structure, and
=item * the 'json' driver, which encodes the data structure as JSON.
=back
A module may return their own 'raw' or 'json' drivers which override these defaults.
=head1 SUBROUTINES
=head2 app
The C<app> subroutine in general takes C<@ARGV> (although it could be any list) and runs the harness.
=cut
sub app {
local @ARGV = @_;
my %args;
GetOptions(
"vendor=s" => \$args{vendor},
"type=s" => \$args{type},
"format=s" => \$args{format},
"output=s" => \$args{output}
) or pod2usage(2);
# Set the defaults
$args{vendor} //= 'Cisco';
$args{type} //= 'ASA';
$args{format} //= 'raw';
$args{output} //= '-'; # STDOUT
# Load the module specified by the command line parameters
my $parser_module_name = "Device::Network::ConfigParser::$args{vendor}::$args{type}";
load $parser_module_name, qw{get_parser get_output_drivers parse_config post_process};
# Check the exports
if (!defined &get_parser ||
!defined &get_output_drivers ||
!defined &parse_config ||
!defined &post_process) {
die "$parser_module_name does not export all required subroutines\n";
}
# Retrieve the parser and the output drivers from the module. If 'raw' doesn't exist,
# it's populated with the default sub from this package.
# The active driver is then selected for use.
my $parser = get_parser();
my $output_drivers = get_output_drivers();
$output_drivers->{raw} //= \&_default_raw_output_driver;
$output_drivers->{json} //= \&_default_json_output_driver;
my $active_output_driver = $output_drivers->{ $args{format} };
if (!defined $active_output_driver || reftype $active_output_driver ne 'CODE' ) {
die "'$args{format}' is not a valid output driver for $parser_module_name\n";
}
# If there are no files specified, we slurp from STDIN
push @ARGV, \*STDIN if !@ARGV;
for my $config_filename (@ARGV) {
# Read in the configuration
my $raw_config = slurp $config_filename;
# Change the name to something sensible so it isn't stringified to something like 'GLOB(0x17c7350)'
$config_filename = 'STDIN' if reftype($config_filename) && reftype($config_filename) eq 'GLOB';
# Call the parser imported from the module.
my $parsed_config = parse_config($parser, $raw_config);
# Perform any post-processing.
my $post_processed_config = post_process($parsed_config);
# Open the file, which could be STDOUT
my $fh;
if ($args{output} eq '-') {
( run in 0.645 second using v1.01-cache-2.11-cpan-f56aa216473 )