Managing Blocks of Code with Editfiles

From Cfwiki

Jump to: navigation, search

In Editfiles Examples I described a method for maintaining the contents of a single file as a whole, using editfiles and some neat tricks for controlling when to update the file contents.

The technique works well for very static files that are only edited by one cfengine configuration, but is lacking when multiple cfengine configurations must maintain individual changes within the same file.

Here I intend to demonstrate a method to allow different cfengine configuration files to maintain blocks of code independently within the same file, without overwriting each others changes.

The goal is to encapsulate the changes using a begin and end tag, and then treat the text between those tags like we did each file in Editfiles Examples.

The tags will incorporate the source cfengine configuration that performed the edit, the revision number, and the host. Any begin/end pair that match the source cfengine configuration file but are not at the current revision are removed, disposing of all old code blocks. A new block of code with fresh tags is appended to the end of the file.

Example cfengine code for maintaining a block of code in a file:

#!/var/cfengine/bin/cfagent -qvKf

######################################################################
# control section

control:

        actionsequence = (     editfiles )

        ############################################################
        # Variables to support RCS data in editing.
        #
        # Because the $'s in RCS tags break regexps, cut out the
        # data we want from a shell.
        # Remember, RCS updates the tags each time we commit.
        #
        RCSRev =    ( ExecResult(/bin/sh -c "echo '$Revision: 1.3 $' | /usr/bin/cut -f2 -d' ' ")  )

        RCSFile =    ( ExecResult(/bin/sh -c "echo '$RCSfile: BlockEdit.cf,v $' | /usr/bin/cut -f2 -d' '")  )

        # Save some typing by combining into a var.
        #
        EditHeader = ( 'CFEngine $(host) $(RCSFile)' )

editfiles:

        { /etc/hosts

                AutoCreate

                ############################################################
                # Locate OLD block of code with BEGIN/END tags
                # that don't match current revision
                #
                # The final delete is required because DeleteToLineMatching
                # doesn't delete the END tag line that it matched to.
                #
                LocateLineMatching "##### BEGIN $(EditHeader).*"
                BeginGroupIfNoMatch "##### BEGIN $(EditHeader) $(RCSRev)"
                        DeleteToLineMatching "##### END $(EditHeader).*"
                        DeleteNLines '1'
                EndGroup

                ############################################################
                # If there were no old blocks, don't abort.
                CatchAbort

                ############################################################
                # Insert block of code with revision tracking if no
                # current block exists
                #
                BeginGroupIfNoLineMatching "##### BEGIN $(EditHeader) $(RCSRev)"

                        ############################################################
                        # Begin block with tag
                        #
                        Append "##### BEGIN $(EditHeader) $(RCSRev)"

                        ############################################################
                        # Code inside block
                        #
                        Append "127.0.0.1                      localhost"
                        Append "192.168.1.254          myrouter"
                        Append "192.168.1.1                    application"

                        ############################################################
                        # Terminate block with tag
                        #
                        Append "##### END $(EditHeader) $(RCSRev)"

                EndGroup
        }

This form of editing is suitable for any file whose contents are not required to be in any particular order, or don't mind customization at the end. It is also handy for any file that needs to be updated by more than one cfengine configuration file (ie: multiple applications that need to add stanzas to httpd.conf).

Please post feedback if you enjoyed this article and found it useful.

--RussellAdams 6-Dec-2004

Personal tools