Rails Rumble wrapped up recently and with that, the end of an exciting 48 hour experience where developers can challenge themselves, prove all their programming skills and create an awesome product from an idea.

This is the third hackathon I’ve participated in since I began working as a professional programmer, and I wanted push myself and create my own version of a continuous integration server.

While creating a continuous integration server we went through a lot of challenges, from user experience design to interesting architectural decisions, but one of the most challenging and interesting situations I went through was running the build jobs from a repository in a virtualized environment. At the very beginning we realized that the safest way to run the tests for a given repository was to isolate the test environment from the web server environment due to because of security risks, so we decided to setup the architecture in the following way:






The idea was to connect to a remote (virtualized) server over the SSH protocol and run the script with a provisioned environment (ruby, rvm, rubygems, postgresql, sqlite, mysql, etc.). We spent some time researching how to connect via SSH using ruby and found a library called Net::SSH which allows you to create SSH connections easily and execute a command. We did some tests and it worked but unfortunately it was very hard to navigate through folders and request a bash environment just like a normal SSH connection from the UNIX terminal, so after a long researching, testing, and reverse engineering many open source projects that use Net::SSH we decided to create abstraction layers for each of its components (use-cases).





By giving single responsibility to each of the classes we were able to easily build the programming interfaces on top of the CI module (see SOLID).

The simplest case scenario, you can connect to a server just by instancing the objects from the top level class of the CI module as following:

Pretty easy, right? Let’s take a look inside the module:

This class is only responsible for setting up the connection parameters that Ci::SSH will handle as a connection string, so we have encapsulated the Ci::SSH work in a lower level of the Ci namespace. You can actually use it outside the Ci::Environment class but you have to customize it as seen in thedef initialize method above. Now let’s take a look at how the Ci::SSH works.

By defining these two classes the usage of Net::SSH becomes pretty straight forward:

By the end of the hackathon, all this made communication possible between the continuous integration environment and the UI. We connected the shell output to a websocket using the pusherservice, so we could push notifications from the server in real time to the user; you can see it live by visiting the actual project from RailsRumble Simple CI.


Let me know via comments on this post or via email antonio@tangosource.com.