Search code examples
bashshellawknagiosnagiosxi

Extract Nagios object definitions from a monolithic configuration file to individual files


I am porting some old Nagios configuration data across from Nagios Core to Nagios XI. Part of this work means that I need to extract some object definitions and place them into individual files named by hostname (example to follow). I can see a number of ways to do it, possibly by writing a script (Perl/Python/PHP - the Nagios XI scripting seems to all be done in PHP). However I was wondering if there was a simpler way to do this, perhaps on the command line using awk or similar? It strikes me that awk can extract lines of text between two delimiting patterns easily enough (e.g. /define host \{/ and /\}/) but I need the output separating into individual files named by the contents of the host_name field.

What is the best approach to this? Am I best off writing a script, or is there a neat awk command (or similar) that can be run from the bash shell on the Nagios XI machines?

Example monolithic file:

define host {
    host_name   testhost1
    use             hosttemplate1
    address                 10.0.0.1
    host_groups                     +linux,all
    contact_groups          +servicedesk
    alias           testhost1
    icon_image      redhat_icon.png
}
define service {
    use     servtemplate1
    host_name   testhost1
    service_groups  +All
    service_description  A Test Service
}
define host {
    host_name   testhost2
    use             hosttemplate2
    address                 10.0.0.2
    host_groups                     +linux,all
    contact_groups          +servicedesk
    alias           testhost2
    icon_image      redhat_icon.png
}

Desired output:

# cat testhost1.cfg
define host {
    host_name   testhost1
    use             hosttemplate1
    address                 10.0.0.1
    host_groups                     +linux,all
    contact_groups          +servicedesk
    alias           testhost1
    icon_image      redhat_icon.png
}
# cat testhost2.cfg
define host {
    host_name   testhost2
    use             hosttemplate2
    address                 10.0.0.2
    host_groups                     +linux,all
    contact_groups          +servicedesk
    alias           testhost2
    icon_image      redhat_icon.png
 }

Now for example I can run a command like this which seems fairly widely used for line extraction:

# gawk ' /define host / {flag=1;next} /}/{flag=0} flag { print }' example.cfg

This chops off the define host and } but that's a relatively easy fix - however it's outputting the data as one stream in the shell.

Is there some clever trick I can implement to do all this including the splitting into individual configuration files from a one liner on the shell, or should I write a script?


Solution

  • Using awk:

    One-liner

    awk '/^define host/{f=1;str=$0;next}/host_name/{h=$NF".cfg"}f{str=str ORS $0}f && /^\}/{print "#"h>h; print str>h; f=""; close(h)}' file
    

    Explanation

    awk '
          /^define host/{                # look for line start with define host
                          f=1            # set variable f to 1
                          str=$0         # set variable str = current line/row/record 
                          next           # go to next line
          } 
          /host_name/{                   # look for line with hostname
                         h=$NF".cfg"     # set variable h with last field value plus ".cfg"
          }
          f{                             # if f was true or 1 then
                         str=str ORS $0  # concatenate variable str with current record 
          }
          f && /^\}/{                    # if f is true and line starts with } then
                         print "#"h > h  # write # hostname to file
                         print str > h   # write the content of variable str to file
                         f=""            # nullify variable
                         close(h)        # close file 
          }
        ' file
    

    Test Results

    Input:

    $ cat file 
    define host {
        host_name   testhost1
        use             hosttemplate1
        address                 10.0.0.1
        host_groups                     +linux,all
        contact_groups          +servicedesk
        alias           testhost1
        icon_image      redhat_icon.png
    }
    define service {
        use     servtemplate1
        host_name   testhost1
        service_groups  +All
        service_description  A Test Service
    }
    define host {
        host_name   testhost2
        use             hosttemplate2
        address                 10.0.0.2
        host_groups                     +linux,all
        contact_groups          +servicedesk
        alias           testhost2
        icon_image      redhat_icon.png
    }
    

    Execution:

    $ awk '/^define host/{f=1;str=$0;next}/host_name/{h=$NF".cfg"}f{str=str ORS $0}f && /^\}/{print "#"h>h; print str>h; f=""; close(h)}' file
    

    Files generated:

    $ cat *.cfg
    #testhost1.cfg
    define host {
        host_name   testhost1
        use             hosttemplate1
        address                 10.0.0.1
        host_groups                     +linux,all
        contact_groups          +servicedesk
        alias           testhost1
        icon_image      redhat_icon.png
    }
    #testhost2.cfg
    define host {
        host_name   testhost2
        use             hosttemplate2
        address                 10.0.0.2
        host_groups                     +linux,all
        contact_groups          +servicedesk
        alias           testhost2
        icon_image      redhat_icon.png
    }
    

    In PHP

    $ cat test.php
    <?php
    preg_match_all('~define host\s+?{[^}]*}~', file_get_contents('file'), $match);
    foreach($match[0] as $config)
    {
        if(preg_match('~host_name\s+([^\s]*)~', $config, $host))
        {
            $file = $host[1].".cfg";
            file_put_contents($file, '#'.$file.PHP_EOL.$config.PHP_EOL);
        }
    }
    ?>
    
    $ php test.php 
    $ ls *.cfg
    testhost1.cfg  testhost2.cfg