Instant Karma: Updating the clones automatically upon push in Mercurial
August 29, 2011 Posted by Emre S. Tasci
Suppose that I have a web server which consists of two identical computers behind a splitter that distributes the incoming requests made to a shared ip. Furthermore, the central repository is being kept on a different computer and as a final thing, assume that I sometimes use the computer located in my office, and sometimes the computer at my home as indicated in the following diagram:
The red arrows indicate the mercurial transfers. You can see that, the changes are only applied to the servers, i.e., nobody codes directly there (no push, only pulls and ups). My two computers can also be thought of two different developers but that part actually isn’t very relevant to this entry’s message. The thing I want to happen is: whenever I push a change into the central repository, I would like to see that it is applied on the servers. In other words I want the following procedures to be automated after the PC@wherever: hg push operation:
- PC@wherever: hg com
- PC@wherever: hg push
- PC@wherever: ssh CentralRepo
- CentralRepo: hg up
- CentralRepo: ssh Server#1
- Server#1: hg pull
- Server#1: hg up
- Server#1: ssh Server#2
- Server#2: hg pull
- Server#2: hg up
Even though I’ll be using Mercurial in this entry, SVN implementation is pretty much similar. After all, we’ll be using the so-called hooks, i.e. the procedures that takes place upon a triggered event such as push.
Since we will be automating (and I’ll be using SSH for the communication between the nodes), it is essential that the nodes can communicate freely via the help of the ssh-keys (all the relevant information including the usage of “hg-ssh” can be found in a previous entry titled ‘Accessing Mercurial with limited SSH access using key and hg-ssh’).
The trigger event is the incoming data to the central repository, so we edit the .hg/hgrc file of the project on the central repository and type:
[hooks]
incoming = .hg/incominghook.sh > /dev/null
This hook just tells the mercurial to execute the ‘incominghook.sh’ script in the .hg directory (relative to the project’s root dir) whenever there’s an incoming data (i.e., “a push to this -central- repository). So what it should do? It should ‘hg up’ the central repository, for starters. Then, it should ‘ping’ the two servers so that they also pull and update from the -now up-to-date- central repository. This is what the incoming.sh script looks like:
#!/bin/sh
# Go to the project's dir no matter where you are
cd /path/to/the/project/repository/
# Update it (since this is the central repo, there is no need to 'pull',
# everybody is pushing to here)
hg up
# Connect to the servers using the id files specifically generated for this purpose
# so that, upon connection, filtered by the command option
ssh -i ~/.ssh/id_rsa_specific_id_for_the_project__central_repo server1
ssh -i ~/.ssh/id_rsa_specific_id_for_the_project__central_repo server2
Again, if it is not very clear how will the servers get into action by a mere SSH connection, I do urge you to check the aforementioned entry.
The ~/.ssh/authorized_keys file on server1 contains the following related entry corresponding to the supplied id being used in the connection made from central repo:
command="/home/sururi/bin/hgpull_project_x.sh",
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAnq.....==sururi@centralRepo (project X)
So that, when “somebody” connects with the relevant key_id file, the server executes the ‘hgpull_project_x.sh’ (located at /home/sururi/bin/) and returns the output, if any. You can guess that this script actually goes to the project’s location, pulls the changes and then ups it. As is evident from the contents of the ‘hgpull_project_x.sh’ script:
cd /path/to/the/project/on/server1
hg pull --ssh "ssh -i ~/.ssh/id_rsa_specific_id_for_the_project__server1" ssh://sururi@centralrepo//path/to/project
hg up
As you can learn from the strongly referred previous entry, the corresponding line on central repo’s authorized_keys file is something like:
command="hg-ssh /path/to/project/",no-port-forwarding, no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB...
and we’re done.
Leave a Reply