The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Mnet::Stanza - Manipulate stanza outline text such as ios configs

SYNOPSIS

    # use this module
    use Mnet::Stanza;

    # read current config from standard input, trim extra spaces
    my $sh_run = undef;
    $sh_run .= "$_\n" while <STDIN>;
    $sh_run = Mnet::Stanza::trim($sh_run);

    # remove and recreate acl if configured acl does not match below
    Mnet::Stanza::ios("
        =ip access-list DMZ
         =permit 192.168.0.0 0.0.255.255
    ", $sh_run);

    # print config applying acl to shutdown interfaces if not present
    my @ints = Mnet::Stanza::parse($sh_run, qr/^interface/);
    foreach my $int (@ints) {
        next if $int !~ /^\s*shutdown/m;
        next if $int =~ /^\s*ip access-group DMZ in/m;
        die "error, $int" if $int !~ /^interface (\S+)/;
        print "interface $1\n";
        print " ip access-group DMZ in\n";
    }

DESCRIPTION

Mnet::Stanza can be used on text arranged in stanzas of indented lines or text in outline format, such as the following:

    line
    stanza 1
     indented line
    stanza 2
     sub-stanza 1
      indented line 1
      indented line 2
      sub-sub-stanza 1
       indented line 1
       indented line 2
    end

In the above example the following would be true:

    stanza 1 contains a single indented line
    stanza 2 contains sub-stanza 1 and everything under sub-stanza 1
    sub-stanza 1 contains two indented lines and a sub-sub-stanza 1
    sub-sub-stanza 1 contains two indented lines

This module can be used to parse cisco ios configs and other similar formats.

FUNCTIONS

Mnet::Stanza implements the functions listed below.

trim

    $output = Mnet::Stanza::trim($input)

The Mnet::Stanza::trim function can be used to normalize stanza spacing and may be useful before calling the diff function or otherwise processing the stanza.

This function modifies the input string as following:

    - remove trailing spaces at the end of all lines of text
    - remove blank lines before, after, and within text
    - remove extra leading spaces while preserving indentation
    - remove extra spaces inside non-description/remark lines
        doesn't modify ios description and remark command lines

A null value will be output if the input is undefined.

Note that in some cases extra spaces in the input may be significant and it may not be appropriate to use this trim function. This must be determined by the developer. Also note that this function does not touch tabs.

parse

    @output = Mnet::Stanza::parse($input, qr/$match_re/)
    $output = Mnet::Stanza::parse($input, qr/$match_re/)

The Mnet::Stanza::parse function can be used to output one or more matching stanza sections from the input text, either as a list of matching stanzas or a single string.

Here's some sample input text:

    hostname test
    interface Ethernet1
     no ip address
     shutdown
    interface Ethernet2
     ip address 1.2.3.4 255.255.255.0

Using an input match_re of qr/^interface/ the following two stanzas are output:

    interface Ethernet1
     no ip address
     shutdown
    interface Ethernet2
     ip address 1.2.3.4 255.255.255.0

Note that blank lines are not considered to terminate stanzas.

Refer also to the Mnet::Stanza::trim function in this module.

diff

    $diff = Mnet::Stanza::diff($old, $new)

The Mnet::Stanza::diff function checks to see if the input old and new stanza strings are the same.

The returned diff value will be set as follows:

    <null>          indicates old and new inputs match
    <undef>         indicates both inputs are undefined
    undef:$a        indicates either new or old input arg is undefined
    line $n: $t     indicates mismatch line number and line text
    other           indicates other mismatch such as extra eol chars

Note that blank lines and all other spaces are significant. Consider using the Mnet::Stanza::trim function to normalize both inputs before calling this function.

ios

    $output = Mnet::Stanza::ios($template, $config)

The Mnet::Stanza::ios fucntion uses a template to check a config for needed config changes, outputting a generated list of overlay config commands that can be applied to the device to bring it into compliance.

The script dies with an error if the template argument is missing. The second config argument is optional and can be set to the current device config.

The output from this function will be commands that need to be added and/or removed from the input config, generated by comparing the input template to the input config. The output will be null if the input config does not need to be updated.

This function is designed to work on templates and configs made up of indented stanzas, as in the following ios config example, showing a global snmp command and a named access-list stanza:

    ! global commands are not indented
    snmp-server community global

    ! a stanza includes lines indented underneath
    ip access-list stanza
     permit ip any any
     deny ip any any

Template lines should start with one of the following characters:

    !   comment

            comments are ignored, they are not propagated to output

    +   add line

            config line should be added if not already present
            to add lines under a stanza refer to '>' below

    >   find stanza

            use to find or create a stanza in the input config
            found stanzas can have '+', '=', and/or '-' lines underneath
            found stanzas are output if child lines generate output

    =   match stanza

            output stanza if not already present and an exact match
            indented lines undeneath to match must also start with '='
            possible to '>' find a stanza and '=' match child sub-stanza

    -   remove line or stanza if present

            remove global command, command under a stanza, or a stanza
            wildcard '*!*' at end of line matches one or more characters
            does not remove lines already checked in the current stanza
            lines to be removed are prefixed by 'no' in the output
            lines already starting with 'no' get the 'no' removed
            to remove commands under a stanza refer above to '>'

Following is an example of how this function can be used to remediate complex ios feature configs:

    # use this module
    use Mnet::Stanza;

    # read current config from standard input
    my $sh_run = undef;
    $sh_run .= "$_\n" while <STDIN>;

    # define ios feature update template string
    #   can be programmatically generated from parsed config
    my $update_remplate = "

        ! check numbered acl, ensure no extra lines
        +access-list 1 permit ip any any
        -access-list 1 *!*

        ! check that this stanza matches exactly
        =ip access-list test
         =permit ip any any

        ! find vlan stanza and ensure acls are applied
        >interface Vlan1
         +ip access-group 1 in
         +ip access-group test out
    ";

    # define ios feature remove template string
    #   used to remove any old config before applying update
    my $remove_template = "

        ! acl automatically removed from interface
        -access-list 1
        -ip access-list test

    ";

    # output overlay config if update is needed
    #   overlay will remove old config before updating with new config
    if (Mnet::Stanza::ios($update_template, $sh_run)) {
        print Mnet::Stanza::ios($remove_template, $sh_run);
        print Mnet::Stanza::ios($update_template);
    }

Note that extra spaces are removed from the template and config inputs using the Mnet::Stanza::trim function. Refer to that function for more info.

SEE ALSO

Mnet

Mnet::Log