-1

I have a text config file sitting in my home directory (linux). This is the format:

ip nat pool nat_pool1 192.168.10.100 192.168.10.100 netmask /24
!
ip route 0.0.0.0 /0 192.168.15.1
!
slb server websrv1 192.168.10.5
  port 80 tcp
!
slb server websrv2 192.168.10.6
  port 80 tcp
!
slb server websrv3 192.168.10.7
  port 80 tcp
!
slb service-group websrv_80 tcp
  member websrv1 80
  member websrv2 80
  member websrv3 80
!
slb virtual-server websrv1 192.168.15.11
  port 80 tcp
    source-nat pool at_pool1
    service-group websrv_80
!
end

I need a script (perl? / python?) that can be fed an argument like this:

script_name virtual-server_name

And then produce output showing the source-nat and service-group details tied to the virtual server. So, in the example config below, if ran "script_name websrv1"

The script would parse for the websrv1 virtual server and display the output along with the source-nat and slb-service-group configuration info tied to it. The script would output something like this:

slb virtual-server websrv1 192.168.15.11
  port 80 tcp
    source-nat pool at_pool1
    service-group websrv_80

slb service-group websrv_80 tcp  
  member websrv1 80  
  member websrv2 80  
  member websrv3 80  

ip nat pool nat_pool1 192.168.10.100 192.168.10.100 netmask /24

An extra benefit would be if it added the websrv1, 2 and 3 lines below it as well. Any help is very much appreciated.

jogle900
  • 13
  • 5

4 Answers4

0

As your config file is structured the first thing your script needs is a section detection. The following would be my first attempt in Perl:

  • read lines from STDIN
  • range operator in scalar context, i.e. as flip-flop, to detect start and end of a section
  • while in the section
    • parse start line to detect type
    • parse other lines
    • process line according to section type
use strict;
use warnings;

while (<STDIN>) {
    chomp;

    if (/^slb\s+/../^!\s*$/) {
        #print "SECTION: $_\n";
        my($type, $remainder);

        # start line
        if      (($type, $remainder) = /^slb\s+(\S+)\s+(.+)/) {
            print "SECTION ${type} START (${remainder})\n";

        # other lines in section
        } elsif (($type, $remainder) = /^\s+(\S+)\s+(.+)/) {
            print "OTHER ${type} LINE (${remainder})\n";

        # end line, i.e. "!"
        } else {
            #print "END LINE: $_\n";
        }
    }
}
exit 0;

Test run with your example:

$ perl dummy.pl <dummy.txt
SECTION server START (websrv1 192.168.10.5)
OTHER port LINE (80 tcp)
SECTION server START (websrv2 192.168.10.6)
OTHER port LINE (80 tcp)
SECTION server START (websrv3 192.168.10.7)
OTHER port LINE (80 tcp)
SECTION service-group START (websrv_80 tcp)
OTHER member LINE (websrv1 80)
OTHER member LINE (websrv2 80)
OTHER member LINE (websrv3 80)
SECTION virtual-server START (websrv1 192.168.15.11)
OTHER port LINE (80 tcp)
OTHER source-nat LINE (pool at_pool1)
OTHER service-group LINE (websrv_80)

Alternative: as your script will need to attach semantic meaning to the parsed content and make connections between different type of "objects" (virtual, server, groups, ...) you should look into writing a real lexer/parser for your config file syntax. In the end that will be less tedious than parsing the lines by hand.

Stefan Becker
  • 5,695
  • 9
  • 20
  • 30
0

This can be done with a relatively simple awk script, modified from this stackoverflow post.

awk '/websrv1/{flag=1}/!/{flag=0;}flag' config-file.conf 

substitute websrv1 as necessary for the search term you are interested in, and config-file.conf for the file to search through.

Marcus
  • 3,216
  • 2
  • 22
  • 22
0

Sinc you didn't show any effort of your own but appreciate help, here is something to get you started with perl:

Do you, by any chance know about

if (cond .. cond) {
}

This can be used in a while loop like this:

while (<>) {
    if (/^slb/ .. /^(!|END)/) {
      ... here you can collect your slb-blocks into a hash
    }
}

If you have read your data into a hash like for example:

'slb service-group websrv_80 tcp' => "  member websrv1 80\n  member websrv2 80\n  member websrv3 80",
'slb virtual-server websrv1 192.168.15.11' => "  port 80 tcp\n    source-nat pool at_pool1\n    service-group websrv_80"

I think it will be easy to iterate over the hash keys, printing out the values. Adittionally you can then parse the output for any additional data to print.

Skeeve
  • 7,188
  • 2
  • 16
  • 26
0

Here is an example of how to get started using Regexp::Grammars:

use strict;
use warnings;
use Regexp::Grammars;

my $parser = qr{   
          <nocontext:>
          <blocks>
          <rule: blocks> (?: <[block]><.block_separator>)*
          <rule: block> <[line]>+
          <token: line> ^(?: $ | (?: (?!(?:end | !))(?: .*?$)))\n?
          <token: block_separator> ^(?: end | !)\s*\n?
}mx;

my $fn = 'config.txt';
open ( my $fh, '<', $fn ) or die "Could not open file '$fn': $!";
my $text = do { local $/; <$fh> };
close $fh;

if ($text =~ $parser) {
    for my $block (@{ $/{blocks}{block} }) {
        print join '', @{ $block->{line} };
        print "\n", '-' x 40, "\n";
    }
}

Output:

ip nat pool nat_pool1 192.168.10.100 192.168.10.100 netmask /24

----------------------------------------
ip route 0.0.0.0 /0 192.168.15.1

----------------------------------------
slb server websrv1 192.168.10.5
  port 80 tcp

----------------------------------------
slb server websrv2 192.168.10.6
  port 80 tcp

----------------------------------------
slb server websrv3 192.168.10.7
  port 80 tcp

----------------------------------------
slb service-group websrv_80 tcp
  member websrv1 80
  member websrv2 80
  member websrv3 80

----------------------------------------
slb virtual-server websrv1 192.168.15.11
  port 80 tcp
    source-nat pool at_pool1
    service-group websrv_80

----------------------------------------
Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174