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.
Accessing Mercurial with limited SSH access using key and hg-ssh
August 28, 2011 Posted by Emre S. Tasci
Today, I wondered about (actually needed) the possibility to be able to limit (and hence connect afterwards) the access to the repository center of mercurial, using SSH.
To limit an SSH connection, you use ssh-keys: you create a pair of keys, private and public, using the ‘ssh-keygen’ command and then adding the public one to the ~/.ssh/authorized_keys. As an example, consider two computers ‘local’ and ‘remote’ and we want to connect to remote from local without having to enter password every time. So, from the console of local, first I create the key pair:
sururi@local:/tmp/tmp$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/sururi/.ssh/id_rsa): ./id_rsa_example
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ./id_rsa_example.
Your public key has been saved in ./id_rsa_example.pub.
The key fingerprint is:
84:59:8d:8c:43:4a:bc:31:ff:5a:12:23:34:45:56:67 sururi@remote
The key's randomart image is:
+--[ RSA 2048]----+
|  oAE*=A+o      |
| .o.=..+=..     |
|  .o...       |
|Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â |
|Â Â Â Â Â Â Â Â XXXÂ Â |
+-----------------+
I didn’t specified any password because I’m intending to have it used automatically (in the hook procedures) and I specified the location of the pair files as the current directory with the names: id_rsa_example & id_rsa_example.pub
Now, I should append the contents of the ‘id_rsa_example.pub’ file to the ./ssh/authorized_keys at the remote computer. To do this, of course, I should be able to connect it via SSH by normal means. So I execute (from the local computer):
ssh your_username@remote 'cat >> ~/.ssh/authorized_keys' < ./id_rsa_example.pub
And from this moment on -hopefully- you should be able to connect without the remote asking for your password (since we’re not using the default place & filename for the key, i.e. ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub, this newly generated key should be included with the “-i” (identity file) option as in: ssh -i /tmp/tmp/id_rsa_example yourusername:remote)… but, that wasn’t exactly what we wanted. We are thinking of a scenario where you’d like to (semi-)freely distribute the SSH access to the central repository to your developers while making sure that they wouldn’t (couldn’t) do something nasty while they are connected to the remote computer.
We can limit the things an SSH-connected user can do to a single thing via the authorized keys option. Checking this file on the remote computer’s ~/.ssh/authorized_keys file, you should see something like:
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAnq5rMLnoab+2F28g/nb58RBENWtX395TuyDFsYkalGaZxrziwDoau/wglkU19DbcAVKgw0p6lMEIuh2iALOppRzxrTgFFhJkL1dxzkugbbPEoSWyfrj9FivzpnxHWgRHQApQeWUBOZhroDTURwfqcyC9SW020CR57jLWfgw+idqwtCu+ZBYmEyHSJcZIH2mWXLrUQ8OalxCFVaLKL50Lpc7V8XJPs+Pg6MPVgfDUqMdjrGkAF7j4viOHTjDWP1h4Ngim70dOeyxWtuqbCbxM4APTShaqET42sj1jHxL2m1dJzXX8s/gEdN0O09hZPhI6rlC+ANWIdJ1vJfODMXWaQ== sururi@local
By adding the “command” option to the beginning of this line would make sure that whenever somebody with the corresponding key connects, that command is run automatically, the results passed back and the connection is terminated afterwards. So, far example. modifying the entry upstairs as:
command="date" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAnq5rMLnoab+2F28g/nb58RBENWtX395TuyDFsYkalGaZxrziwDoau/wglkU19DbcAVKgw0p6lMEIuh2iALOppRzxrTgFFhJkL1dxzkugbbPEoSWyfrj9FivzpnxHWgRHQApQeWUBOZhroDTURwfqcyC9SW020CR57jLWfgw+idqwtCu+ZBYmEyHSJcZIH2mWXLrUQ8OalxCFVaLKL50Lpc7V8XJPs+Pg6MPVgfDUqMdjrGkAF7j4viOHTjDWP1h4Ngim70dOeyxWtuqbCbxM4APTShaqET42sj1jHxL2m1dJzXX8s/gEdN0O09hZPhI6rlC+ANWIdJ1vJfODMXWaQ== sururi@local== sururi@vala
would cause the following behaviour from the remote:
sururi@local:~$ ssh -i /tmp/tmp/id_rsa_example sururi@remote
Sun Aug 28 22:05:54 CEST 2011
Connection to remote closed.
I’m a bit tired now writing in full details, so will skip some obvious things from now on. Mercurial has an SSH-wrapper called ‘hg-ssh’ exactly for this purpose, and you can use it by specifying the paths of the repositories as command arguments as in:
command="hg-ssh /path/to/repository" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAnq5rMLnoab+2F28g/nb58RBENWtX395TuyDFsYkalGaZxrziwDoau/wglkU19DbcAVKgw0p6lMEIuh2iALOppRzxrTgFFhJkL1dxzkugbbPEoSWyfrj9FivzpnxHWgRHQApQeWUBOZhroDTURwfqcyC9SW020CR57jLWfgw+idqwtCu+ZBYmEyHSJcZIH2mWXLrUQ8OalxCFVaLKL50Lpc7V8XJPs+Pg6MPVgfDUqMdjrGkAF7j4viOHTjDWP1h4Ngim70dOeyxWtuqbCbxM4APTShaqET42sj1jHxL2m1dJzXX8s/gEdN0O09hZPhI6rlC+ANWIdJ1vJfODMXWaQ== sururi@local
(and for more security, I would suggest you include the other options as well, such as:)
command="hg-ssh /path/to/repository",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAnq5rMLnoab+2F28g/nb58RBENWtX395TuyDFsYkalGaZxrziwDoau/wglkU19DbcAVKgw0p6lMEIuh2iALOppRzxrTgFFhJkL1dxzkugbbPEoSWyfrj9FivzpnxHWgRHQApQeWUBOZhroDTURwfqcyC9SW020CR57jLWfgw+idqwtCu+ZBYmEyHSJcZIH2mWXLrUQ8OalxCFVaLKL50Lpc7V8XJPs+Pg6MPVgfDUqMdjrGkAF7j4viOHTjDWP1h4Ngim70dOeyxWtuqbCbxM4APTShaqET42sj1jHxL2m1dJzXX8s/gEdN0O09hZPhI6rlC+ANWIdJ1vJfODMXWaQ== sururi@local
and you can pull now on the local computer from the central repository at the remote computer with a command like:
sururi@local:~/project$ hg pull --ssh "ssh -i /tmp/tmp/id_rsa_example" ssh://sururi@remote//path/to/repo
pulling from ssh://sururi@remote//path/to/repo
searching for changes
no changes found
from SVN to Mercurial
August 23, 2011 Posted by Emre S. Tasci
I’ve been using SVN for revision control system for some time. I certainly benefited from it to organize or fall-back to a stable version (“the good old times”) when I was in trouble while I was computing solo but there were two things that always upset me while using it:
- Commiting meant publishing: This issue might be worked around when you have your trunk (we actually have the trunk for the ‘most recent’ status and a ‘released’ branch for the tested and stable programs of that trunk) and each of the developers play in their branches until it looks OK and hence merge it to trunk (and hopefully eventually make it to the ‘released’ branch), but the problem is, most of the time I’m in the middle of the coding process (in my branch) and it would be nice if I didn’t affect the main repository everytime I made a commit (it’s really not very nice) – in other words, even in my branch I would like to save while not making them available. The answer to this lies of course in distributed revision control systems (dvcs).
- Merging: Merging is hell in SVN when you have many developers. Been there, suffered that.
I had heard of git and bazaar but -for some reasons I don’t know why- never had taken the step to give them a try. Very recently, in a scientific gathering, one of the participants suggested me to use mercurial. The interesting thing about this is, he was suggesting it as a means to enable an “undo” option for a -scientifing- refinement program which has the tendency to update your files in according to the changes you applied. I know this sounds natural but when you tried some method and it didn’t worked, you couldn’t go just one step back and use a different method – you have to start from scratch with your initial input file and apply the methods so far but the last consecutively over again. So, my friend was actually recommending me to use a revision control system for the work files (which can be done perfectly well via SVN, by the way) and he happened to be using mercurial. He suggested to check this website by Joel Spolsky (http://hginit.com/) to get it going and the website is very intriguing, indeed. So I have been running some tests to get my feet wet and it was going so well until I found that the log command didn’t reveal the list of the changes made upon the files per changeset (‘revision’ in terms of SVN). I searched and searched and at the end I found the solution on hg tip (http://hgtip.com/tips/advanced/2010-01-15-styling-mercurials-cli/) website by Steve Losh. His ‘Nice Log’ script was exactly what I was looking for plus some additional effective logging templates.
I don’t think for our big project I can make the switch from SVN to Mercurial, but from now on, I’ll be ‘hg init’ing instead of ‘svnadmin create’ing for the projects to come.