Stjepan Groš

Keeping configuration files in SVN

Note Check the following project.

On this page I'll describe several possibilities to keep server configuration files in a subversion. In this scenario we have the following requirements:

  1. We want to have complete history of all the configuration changes.
  2. The configuration files have to bi in-place. In other words we don't want to manually copy files into working copy and than do commit. Likewise, we don't want to checkout some revision in a working copy and then copy it to it's intended location.

This is a work in progress and as I learn I'll change it to reflect my newest thinking about this. In case you have any comments/critiques/suggestions please mail it to me. I can also open comment section on a blog.

Prerequisites

You'll need to have subversion client installed. Note that the procedure described here will work only with subversion 1.5 and later. Prior versions have two shortcomigs and some workarounds are specified at the end of this document under heading Older SVN versions.

In case your select that your repository is accessible over the network, you'll also need either of these:

  1. Apache Web server with mod_dav module, or
  2. ssh server with svn server

Initializing SVN repository

Repository can be on a local host, or on a remote host. In case it's on the remote host be careful that your configuration files will be transmitted over the network and you must use encryption to protect data in transit. Furthermore, the host with the repository has to be properly secured. If this host is breached, your complete network is in danger.

To initialize repository, just go to the directory where it will be placed and issue the following command:

svnadmin create .

This will create all the necessary files for repository in a current directory.

I'll assume from now on that the variable SVNPATH is the directory where the previous command was issued.

In the following subsections we discuss different methods of accessing repository. You can select more than one if you wish, but I recommend for a start that you use only one and stick with it until everything works as expected. The main goal of the following subsections is to define variable SVNURL that will be used in the following sections.

Local repository

This is a simplest case. The SVNURL variable in this case is formed as follows (using sh/bash syntax):

SVNURL="file://"${SVNPATH}

Apache+mod_dav access

Configure apache with mod_dav (TBD: how to configure apache)

Create and distribute certificates (TBD: how to do that)

The SVNURL in this case is formed as follows

SVNURL="https://"${SVNPATH}

Just one note here. If you use a single repository for multiple host than maybe it's a good practice that you create subdirectory for each host you plan to maintain in SVN. This method of keeping track of configuration file changes is not appropriate for large installations so in most cases short hostname can be used for the directory name. In some cases you might use IP addresses or FQDN.

ssh+svn access

TBD

Make initial import and check-out

You'll do this once, when you start to use SVN on particular host.

After repository has been initialized and all the necessary mechanisms to access it are in place, the first step is to do initial import. At this time I think that the best to add main directories. For example, /etc is a directory you'll certainly want to have in your repository, so we'll add it. This is accomplished with the following command:

svn import --depth empty /etc ${SVNURL}/etc -m 'Importing /etc directory'

Note that the ${SVNURL}/etc is mandatory because otherwise import will not work.

The next thing is to checkout repository so that working copy is identical to the real /etc directory. Note that this step is done in the root directory of the particular host:

# cd /
# svn co ${SVNURL}

If you go now into /etc directory and execute svn status command you'll get large number of lines, each one starting with a question mark. This useless output makes it hard to spot what has changed. To get rid of this useless output, you can either execute each time the following command:

svn status | grep -v ^?

or you can tell SVN to ignore unversioned files. We'll do the letter using the following commands:

# svn propset svn:ignore \* .
# svn ci

Note that you have to do check in after changing property. svn status will now immediately exit without any output. The trick here is that svn doesn't ignore versioned files even though it is told to ignore everything.

This concludes initial setup. What follows is a regular use of this feature.

Frequently used actions

The following actions will be frequently used in this setup:

Adding new files and directories

To add new configuran file or directory under revision control use the normal subversion procedures.

svn add <file>

There could be a problem here that you have to be avare of in order to be able to resolve it. For example, if you added only /etc directory and then you want to add file /etc/sysconfig/ifcfg-eth0 it wont work because /etc/sysconfig is not under the revision file. In this case you'll have to first add directory and then the file itself. To add sysconfig do the following:

svn add --depth empty sysconfig

Now, you can add necessary files under revision control. Note that the option --depth empty is mandatory, otherwise you'll add all the files in the given subdirectory.

One additional recommendation: Add the original version of the file into subversion, i.e. before making any changes!

Making changes to configurations

Do the changes to the configuration files as usual. The difference is that you have to do a commit after the changes are done. It is important to be self disciplined here or otherwise there is no point in this whole work.

Reverting changes

Workflow

Now, these are the steps used to maintain some server. Suppose that you have to add some new feature. This might be accomplished like this:

  1. You start with some changes in the configuration file and appropriate testings to see if they work as expected.
  2. At some point you might find out that the changes you've made are messed up and that you have to start over. That's easy. Just run the followig command:
    svn revert <filename>
    
  3. When you've made all the necessary changes you can leave this configuration to run for a few days, just to be sure everything works as expected. Then, when everything is ok, commit changes to the repository:
    svn ci
    
  4. If, by any chance, at some later time you conclude that the changes are not necessary, or they don't work as expected, it's easy to back up. Just pull previous version from the repository:
    svn info <file>        # To find revision number, let's say it's N
    svn export ${SVNREPO} -r N-1 <pathandfile>
    
  5. If, on the other hand, you want to see what has changed between two version, use the diff subcommand to find out
    svn diff TBD
    

Automated check-in

Even though I sad that you have to be disciplined with this approach, errors are expected because it's normal that human beings make mistakes. Thus, to workaround this, you can use two approaches, both based on a cron job.

  1. The cron jobs checks periodically if there are changes in working copy and warns via email about that, or
  2. The same as the previous but instead of warning does an automatic commit.

Note that in both cases, especially in the second case, you have to be careful not to do automatic commit in the middle of making changes in the configuration files.

Removing revision control

If you ever decide to remove revision control from the files, it's easy to do. Just search for all the .svn subdirectories and remove them. Also, you can remove directory with the repository.

Older SVN versions

In SVN prior to version 1.5 certain options/functionalities are missing. Those are:

  1. there is no --depth option, and thus, you can not import only a top level directory - at least I don't know a way to do it.
  2. the checkout subcommand doesn't have --force option so you can not do inplace checkout.

In order to make a check-in you'll need to create temporary directory hierarchy and then check in those. Unless, of course, you want to import some directory with all the files (and possibily directories) within this directory. In that case, nothing special has to be done.

To check-out, because of a missing --force option, you'll need to make it in some temporary directory and then move all the .svn directories in their respective places. The rest from the temporary working copy you can safely remove.

The other option for check-out is to remove original directory and then do check out. But don't do this with directories that have files that are not under the supervision of SVN, futhermore, don't do this on system directories. You've been warned!.