Jul 2007

Configuring and Scripting WEBDAV Subversion

Subversion is a great system for centralized repository usage and administration. One of the good (pragmatic?) things about subversion is the simple built in access method using the svn protocol. While the svn protocol is good; using the webdav capability for managing repositories is definitely a nice touch. Managing a lot of repositories can be challenging to say the least. In this series a quick look at setting up a single webdav based repository; a simplistic script to add repositories, a script to manage user and finally a full blown shell program for managing webdav based subversion repositories.

Configuring and Setting up Webdav Repos by Hand

In the example, a repository called foo is used. The repository will reside in /var/subversion/foo. Webdav auth files are in /var/htpasswds/. The following pre-requisites are needed:

  • httpd (preferably configured and working).
  • subversion

Getting the Packages

First and foremost the apache installation needs to have the appropriate module installed. Packages will be used in the following example. On RPM based systems yum or up2date can be used to seek out the packages:

yum search dav | grep -i svn

or

up2date search dav | grep -i svn

And on apt systems:

apt-cache search dav | grep svn

Somewhere in the output will be something akin to webdav+svn or just dav+svn - that is what is needed. In the examples below httpd-dav+svn is used:

{yum,up2date,apt-get} install httpd-dav+svn

All done - time to get on to setting up a repository.

Initializing the Repository

Not unlike a standard repository, setting up a new one makes use of the svnadmin command for the initialization:

mkdir /var/subversion
svnadmin init /var/subversion/foo

At this point either an initial tree can be imported or trunk/branch/patch trees added to the repository.

The htaccess Method

In /etc/httpd/conf/httpd.conf either an include can be added for authentication or using one of the default includes in /etc/httpd/conf.d/ (such as the svn one) can be used, In this example a separate include is used:

echo "Include conf/dav_svn.auth" >> /etc/httpd/conf/httpd.conf
touch /etc/httpd/conf/dav_svn.auth
/etc/init.d/httpd restart

On some systems the service utility can be used to restart services:

service httpd restart

Now it is time to add an entry into the dav_svn.auth file:

# webdav entry for foo
<Location /svn/foo>
        DAV svn
        SVNPath /var/subversion/foo/

        AuthType Basic
        AuthName Foo
        AuthUserFile /var/htpasswds/foo

        require valid-user
        Order deny,allow
</Location>

Note that the entry also points to the htpasswd file. Finally, create the users:

htpasswd /var/htpasswds/foo user1
htpasswd /var/htpasswds/foo user2
...
Permissions

The repository needs to be accessible by the webserver. Make sure that the user and group name reflect the apache dictated ones: example:

chown -R apache:root /var/subversion/foo

The htpasswd command allows for input of the password or just use pwgen - in the bash shell a pwgen password can be copied right into the password prompt question of htpasswd. This is all great but what happens when a new repository needs to be created or 6 new repositories? Then it is time to script.

Scripting Tasks

Now two new repositories need to be added and there is no end in sight. Several problems have cropped up:

  1. A quick subversion add script would be great....
  2. Managing users who can cross repositories....
  3. Correctness for all of the above.

Before the topics are addressed, first the common pieces, as with many things at this site there is always the preferred common bits. For these two scripts (for they are to be separate) the common bits are script name, trapping and bombing out:

PROG=${0##*/}
TOPPID=$$

trap "exit 1" 1 2 3 15
...
#-----------------------------------------------------------------------------
# bomb - Simple death routine; display ERRORMESSAGE, kill TOPPID and exit.
#
# requires: ERRORMESSAGE
# returns : exit 1
#-----------------------------------------------------------------------------
bomb()
{
        cat >&2 <<ERRORMESSAGE

ERROR: $@
*** ${PROG} aborted ***
ERRORMESSAGE
        kill ${TOPPID}      # in case we were invoked from a subshell
        exit 1
}

Done, time for the svnadd.sh script. In this new world (also known as moving target) a generic user with a default password for the administrators to test is added. The steps for automatically creating a new repository are:

  • Append a new entry to the authorization file.
  • Create the repository.
  • Chown permissions to match the webserver user.
  • Add the default user.
  • Restart the webserver.

While the list of tasks looks scary, it most certainly is simple to implement.

repo=$1
webdav_fp=/etc/httpd/conf/webdav_svn.auth
repotop=/var/subversion
htaccess=/var/htpasswds

So all of the file handles needed are prepped...

Appending an Entry

The shell is amazing because of the pipe method of connecting pieces together. To add an entry a simple echo will suffice:

append_webdav_entry()
{
        echo "Adding an entry to ${webdav_fp} for ${repo}"
echo "
# webdav entry for ${repo}
<Location /svn/${repo}>
        DAV svn
        SVNPath /var/subversion/${repo}/

        AuthType Basic
        AuthName \"${repo} SVN\"
        AuthUserFile /var/htpasswds/${repo}

        require valid-user
        Order deny,allow
</Location>
" >> $webdav_fp || bomb "Could not add entry to ${webdav_fp}"
}
Usage

There is always room for ye olde usage() message: [1]

#-----------------------------------------------------------------------------
# usage - usage message
#-----------------------------------------------------------------------------
usage()
{
        cat <<_usage_
Usage: ${PROG} repository_name
Usage: ${PROG} usage
}
The Rest...

The remaining steps can actually be performed from the shell script's main routine ; first the top portion of main():

#-----------------------------------------------------------------------------
# Main
#-----------------------------------------------------------------------------

# If no arguments were specified then... wooops...
if [ $# -eq 0 ];then
    echo "No repo name specified"
    usage
    exit 1
fi

# If the user can't remember...
if [ "$repo" = 'usage']; then
        usage
        exit 0
fi

if [ -d $repotop/$repo ] ; then
        bomb "Error: It looks like that repo exists!"
fi

Pretty self explanatory stuff, if the user forgot to enter a repository name then bomb, if the user typed usage as the argument then print the message. It is worth noting that a repository called usage cannot be created with this script. Last and not least - if a directory exists there bomb() out. With the starting point of the main routine the script is pretty much ready to go:

append_webdav_entry # Call append_webdav and build apache entry

# run the svnadmin command
echo "Creating Repository"
svnadmin create $repotop/$repo ||
        bomb "Could not create a new repo at ${repotop}/${repo}"

# fixup permissions
echo "Chowning the new repo to apache"
chown -R apache:root $repotop/$repo ||
        bomb "Could set proper permissions on ${repotop}/${repo}"

# add our default user with our default password
echo "Adding svn user in ${htaccess}/${repo}"
htpasswd -b -c $htaccess/$repo svn <password> ||
        bomb "Could not add svn user to ${htaccess}/${repo}"

# Ummm .. restart apache - we do not use service here as it is not +DAportable
echo "Restarting Apache"
/etc/init.d/httpd restart

exit 0

Outside of the call to append_webdav_entry() the script repeats the manual steps outlined in the first section of the text: which is precisely what scripting for administration is about.

Summary & Next Time

Scripting is the system administrator's friend. Seeing and identifying tasks that are often repeated is the key to success regardless of how much tribal [2] knowledge goes into them; if done correctly then there is nothing to worry about.

Footnotes
  1. Note in this example instead of a plain echo a cat is used. The effect is similar, however, the difference is here to show the different methods.
  2. Tribal knowledge in IT terms is information passed literally from one person to the other with zero (even in code) documentation. In pure code terms it could be thought of as hard path coding.