Successfully Running svnsync through svn+ssh from post-commit and post-revprop-change Hooks

Submitted by Eus
on March 31, 2009 - 7:36pm

One day after I had successfully set up a subversion mirror and kept it in sync with svnsync through svn+ssh protocol as described here: http://blog.codefront.net/2007/03/31/setting-up-svnsync-ed-mirrored-svn-..., I would like to have the sync happen automatically everytime there was a commit. Oh, the blog didn't mention anything about svn+ssh protocol, but it was easily done following the subversion manual itself. So, I coded post-commit and post-revprop-change hooks as described here: http://journal.paul.querna.org/articles/2006/09/14/using-svnsync. However, as Chu Yeow mentioned in his blog that he settled with cron to do the sync because the hooks method didn't work, it also didn't work for me. Both machines were using GNU/Linux Ubuntu 8.04 Desktop.

Googling for several related keywords didn't turn up any useful result, so I tried to figure it out myself. The content of post-commit hook was as follows:

svnsync --non-interactive sync svn+ssh://10.0.0.103/var/lib/svn &

That didn't work. After three commits and manually performing the sync, I realized that the IP address was wrong since the machine didn't reside in the local network anymore. So, I changed it to:

svnsync --non-interactive sync svn+ssh://mydomain.com/var/lib/svn &

That didn't work either. After another commit and manually performing the sync, I realized that the IP address of the mirroring machine was dynamic not static. So, although I utilized public-private key authentication for the SSH session to avoid the interactive blocking password prompt, I was still prompted with a prompt like the following one:

The authenticity of host '202.192.33.21 (202.192.33.21)' can't be established.
RSA key fingerprint is 36:da:77:63:d9:29:64:17:56:c5:d3:2c:98:fa:98:78.
Are you sure you want to continue connecting (yes/no)?

Okay, I turned it off by doing:

$ echo "StrictHostKeyChecking=no" >> ~/.ssh/config

Still, it didn't work. Next, I realized that perhaps the command had to be written in full as follows:

/usr/bin/svnsync --non-interactive sync svn+ssh://mydomain.com/var/lib/svn &

Nope, it didn't work. Finally, I realized that because svnserve, which was the daemon that invoked the hooks, was owned by root, the hooks were executed with effective UID of root, and in turn, executed snvsync and started the SSH session as root. If the SSH session was started as root, surely the SSH would take its configuration from the home directory of root, not from the one of the user account in which I put the SSH private key and the SSH config file. So, I changed the command in the post-commit hook as follows:

sudo -u svn_admin /usr/bin/svnsync --non-interactive sync svn+ssh://mydomain.com/var/lib/svn &

This one works! To make the command in post-revprop-change hook work, simply just follow the same pattern.

To conclude, the following is the checlist to successfully run svnsync utilizing svn+ssh channel with post-commit and post-revprop-change hooks:
1. Ensure that the IP address of the mirror is correct.
2. Ensure that the IP address of the mirror is static. Otherwise, set SSH StrictHostKeyChecking to `no'.
3. Use a full path to the svnsync executable.
4. Use `sudo -u' to ensure that the correct home directory is used to find the SSH private key as well as the config file.

Keywords: ubuntu svnsync svn+ssh post hook

Ops, it needs -H as well

Eus
on
April 17, 2009 - 3:51am

Hi Ho!

Some days ago the mirror server machine had an HD crash and so lost all of its data. Reinstalling everything up and setting up the mirror repository as well gave me a surprise: the post-commit synchronization described above didn't work anymore!

To find out the reason, I used the following command in the post-commit script:

sudo -u svn_admin /usr/bin/svnsync --non-interactive sync svn+ssh://mydomain.com/var/lib/svn > /tmp/eus-commit.txt 2>&1 &

It showed the following error message:

svnsync: Can't get password

Curiously enough, previously my method really worked since I saw that the mirror stayed in sync before it crashed. Well, perhaps some package updates have caused this behavior to change.

In short, the problem lies on finding the proper home directory again as shown in the following output when the above command in the post-commit script was run with `strace':

lstat64("/root/.subversion/auth/svn.simple/9d93e889ee9e820bd678b559e707542c", 0xbf9ccf8c) = -1 ENOENT (No such file or directory)

Okay, it turned out that `sudo -u testing-server-root' does not set the home directory to that of user testing-server-root. The fix according to the man page of `sudo' is to use `-H'. So, the complete new command is:

sudo -H -u svn_admin /usr/bin/svnsync --non-interactive sync svn+ssh://mydomain.com/var/lib/svn > /tmp/eus-commit.txt 2>&1 &

Heh, this is weird since without `-H', SSH can correctly find the public key of user testing-server-root in `/home/testing-server-root/.ssh/'. Well, I bet `svn' and `ssh' employ a different mechanism to determine the UID to find the proper home directory.

Best regards,
Eus (FSF member #4445)

In this digital era, where computing technology is pervasive,
your freedom depends on the software controlling those computing devices.

Join free software movement today!
It is free as in freedom, not as in free beer!

Join: http://www.fsf.org/jf?referrer=4445

Step-by-step

Eus
on
April 22, 2009 - 5:11am

Hi Ho!

It turned out that the steps that I took to setup an SVN mirror repository has differred from my reference sources.
My setup is that the source repository resides in a private network and is accessed via svn:// while the mirror repository resides in the public Internet and is accessed via svn+ssh://. The mirror machine is setup within the local network, after which it will be deployed in the public Internet.
The steps are as follows:

  • Create a Subversion repository in Mirror Machine (e.g., svnadmin create REPO_DIR) as a user that can perform `sudo' (e.g., USER_A).
  • Create a user who will do the synchronization job in Mirror Machine. The user should not be able to login unless via public-private key authentication of SSH (e.g., adduser svnsync --home REPO_DIR --no-create-home --disabled-password) so that no one will accidentally login as the synchronization user and mess everything up.
  • Activate the pre-revprop-change hook to only permit a modification by the synchronization user (e.g., vi REPO_DIR/hooks/pre-revprop-change; chmod a+x REPO_DIR/hooks/pre-revprop-change). The content of the hook should be like the following one:
REPOS="$1"
REV="$2"
USER="$3"
PROPNAME="$4"
ACTION="$5"

if [ "$USER" = svnsync ]; then exit 0; fi

echo "This is a mirror repository that is unwrittable by normal users" >&2
exit 1
  • Let everything under REPO_DIR be owned by the synchronization user (e.g., sudo chown -R svnsync REPO_DIR).
  • Initialize the mirror repo as the synchronization user (e.g., sudo -u svnsync svnsync init file://REPO_DIR svn://SOURCE_REPO_MACHINE).
  • Run an initial synchronization as the synchronization user (e.g., sudo -u svnsync svnsync sync file://REPO_DIR).
  • Create directory .ssh in the home directory of the synchronization user (e.g., sudo -u svnsync mkdir SVNSYNC_HOME_DIR/.ssh).
  • Now switch to the machine hosting the source repository and log in there as any user that you like (e.g., USER_X).
  • Generate an SSH key for USER_X (e.g., ssh-keygen) and let the public and private keys be stored in the default location in addition to not entering any passphrase when asked.
  • Turn off StrictHostKeyChecking if Mirror Machine doesn't have a static IP (e.g., echo "StrictHostKeyCheckingNo" >> .ssh/config).
  • Add the generated public key to the synchronization user's SSH authorized keys in Mirror Machine (e.g., scp USER_X_HOME_DIR/.ssh/id_rsa.pub USER_A@MIRROR_MACHINE:/tmp/ && ssh USER_A@MIRROR_MACHINE 'sudo -u svnsync bash -c "cat /tmp/id_rsa.pub >> SVNSYNC_HOME_DIR/.ssh/authorized_keys"'
  • As mentioned in the subversion manual regarding SSH tunneling tricks (http://svnbook.red-bean.com/en/1.5/svn.serverconfig.svnserve.html#svn.se...), I prefer the svnserve in Mirror Machine to directly serve the source repository with `-r' (e.g., ssh USER_A@MIRROR_MACHINE "sudo -u svnsync sed -i -e '\$ s%^%command=\"svnserve -t -r SOURCE_REPO_DIR\",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty %' SVNSYNC_HOME_DIR/.ssh/authorized_keys") so that I don't have to specify the complete path of the source repository during synchronization.
  • Make sure that USER_X can read the source repository (e.g., svn log -r HEAD svn://SOURCE_REPO_MACHINE). If by default USER_X is allowed to read the source repository, either there will be no password prompt or there will be one that has to be filled with the subversion password of USER_X. If not, just enter a wrong password and a username prompt will appear so that USER_X can read the repository as another subversion user.
  • Activate the post-commit hook of the source repository to perform an automatic synchronization (e.g., vi SOURCE_REPO_DIR/hooks/post-commit; chmod a+x SOURCE_REPO_DIR/hooks/post-commit) and put the following code into it:
REPOS="$1"
REV="$2"

sudo -H -u USER_X /usr/bin/svnsync --non-interactive sync svn+ssh://svnsync@MIRROR_MACHINE &
exit 0
  • Activate the post-revprop-change hook of the source repository to perform an automatic synchronization (e.g., vi SOURCE_REPO_DIR/hooks/post-revprop-change && chmod a+x SOURCE_REPO_DIR/hooks/post-revprop-change) and put the following code into it:
REPOS="$1"
REV="$2"
USER="$3"
PROPNAME="$4"
ACTION="$5"

sudo -H -u USER_X /usr/bin/svnsync --non-interactive copy-revprops svn+ssh://svnsync@MIRROR_MACHINE "$REV" &
exit 0

That's it.

Best regards,
Eus (FSF member #4445)

In this digital era, where computing technology is pervasive, your freedom depends on the software controlling those computing devices.

Join free software movement today! It is free as in freedom, not as in free beer!

Join: http://www.fsf.org/jf?referrer=4445

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.