Published by breki on 13 Jan 2009 at 03:05 pm
Automatic Software Publishing/Distributing Agent
This is a brainstorming post about an idea I’m toying with since morning.
The Problem
First let me describe the problem. Our team is into continuous integration (CI) and we are usually using multiple servers in the CI process: one for building the code and one for integration or acceptance tests. We usually use CruiseControl.NET project(s) to run the initial build and then push the build package onto an integration server (which also uses CruiseControl) to be tested thoroughly. This works, but the problem is writing and setting up scripts to wire all these things together. It boils down to several steps:
- Packaging multiple files into a ZIP package.
- Transferring the package to a remote location.
- Unzipping the package there.
- Executing a script or executable from the package.
- Pushing the results somewhere else.
These steps apply for various procedures, from deploying software to running integration or GUI tests. So basically we have a package we want to run on a remote computer. My usual approach was to have a custom batch files on the remote computer which unzip the package and then run executables inside. The problem is that:
- This is a custom solution for each individual situation. Every time we encounter another such scenario, new batch files need to be prepared.
- It requires pre-installation (i.e. manually copying of these batch scripts to the right place) before the actual process can be started. And again, each scenario requires its own pre-installation.
- CruiseControl.NET: although it is flexibile enough to allow this kind of usage, it is too cumbersome to set up.
- Since the scripting code runs on physically separate locations, they it is also separated into multiple source code files, which means an additional effort is needed to maintain them (keep them in sync).
The Solution
What I was thinking about is some sort of a service (let’s call it Agent) that would accept requests for publishing certain files to a remote location and then running client-specified file(s). The Agent would have a .NET client library which would look like this:
{
publisher.Publish(
PublishingMode.ZippedFile,
@"..\..\IntegrationTests.zip",
@"C:\temp\IntegrationTests",
@"RunTests.exe");
}
The Agent would of course have to be running on the remote machine. The client library would take care of zipping files into a single package (if necessary) and sending them to the remote publisher service. The remote publisher service would unzip the package to the requested location (in this case "C:\temp\IntegrationTests") and run the requested executable ("RunTests.exe"). Some things to note:
- The call to Publish() would return after the files have been transferred to the remote computer. The actual execution on the remote machine would then proceed asynchronously.
- There would have to be some kind of way to specify which user accounts have access to the Agent. Only those users would be allowed to publish stuff.
- The executable would run under the Agent’s Windows service account.
- I still haven’t figured out what kind of protocol to use to actually transfer the files (HTTP?).
- The Agent should be able to run either from a command-line or as a Windows service (much like CruiseControl.NET does).
- It should require the minimal effort to install, configure and maintain once it has been set up.
I should also note that Agents should only run on internal build/test servers, not production ones, since this kind of approach poses a considerable security risk – so I’m not saying it’s secure.
Final Thoughts
Agents would be installed only once and access configured for users that actually use them. After that the service would be available at all times to process various publishing requests of the CI process(es).
As I said from the start, this is just an idea. We’ll see if anything comes out of it


Jean-Philippe Daigle on 14 Jan 2009 at 16:52 #
Firstly, a tip on running multiple CruiseControl setups: when I need several build/test servers to run similar CruiseControl configs, the easiest thing to do is to have a single master CruiseControl config checked into SVN (along with all the binaries/jar files), and have its config.xml refer to an external properties file with the machine name (cruise-properties-${MACHINE}.properties). This way the whole config is shared between machines, except variable properties, like how to label the builds and emails, etc. Adding a new machine is just a matter of checking out the whole tree onto it and creating a new property file. [I haven't tried CruiseControl.NET, but it probably has similar concepts.]
Now, for your job runner service – I think there’s a good idea behind this, but its scope should be limited. Your description is conflating two problems: deploying builds to a test host, and triggering a remote test.
The file deployment problem is already solved. The remote asynchronous job triggering isn’t, so this project might do well to focus only on the second part, and it would be a really useful tool.
Deployment: Your regular build script already produces a staging directory and a compressed archive. It’s trivial to just rsync the whole staging directory to a testing server, or a central file server, or scp the compressed archive to each test host (Ant, for example, has an optional task useful for this). Your testing server, whatever the OS, could also just mount the build server’s output share into its own filesystem and run from there. Perhaps a cleaner approach is to concentrate this responsibility on the test runner, so there’s no coupling between the build host and the test rigs – I do this by having the test job pull down the latest build whenever it starts up. You mention the annoyance of writing a separate script each time, but it doesn’t have to be that way. It’s quite easy to write a simple generic Ant script that takes in a project name and pulls down the latest build for that project from your deployment server, extracts it locally, and exits. A generic script like this can be used across all your projects and build machines, as long as it’s called with different arguments.
So I think remote triggering jobs (maybe using an XML-RPC request to your new service?) is where the exciting unsolved problems are
Jean-Philippe Daigle on 14 Jan 2009 at 16:54 #
Argh, the comment form chewed up angle brackets. The sentence “Ant, for example, has an optional task useful for this”, should have been “Ant, for example, has an optional <SCP> task useful for this”
breki on 14 Jan 2009 at 18:38 #
Hi, Jean-Philippe,
Thanks for your comment. In fact I was preparing a continuation post today which mentions SCP and SSH as a way to do this kind of work, I’ll also mention your suggestions in it. As you will see, I also took a wider look at the whole thing – running distributed CI processes, which I guess is be the opposite of what you’re suggesting (concentrating on just the remote invocation). Well as long as this is just brainstorming (=daydreaming), I guess I’m OK
As for CruiseControl external properties, looks like CCNet also supports them through the configuration preprocessor (http://confluence.public.thoughtworks.org/display/CCNET/Configuration+Preprocessor), but I haven’t used this feature so far. The main problem I have with CCNet is that it doesn’t really do distributed builds – by “really” I mean that, yes, you can set up triggers between projects, but they are in essence treated as separate projects, which makes them harder to monitor and maintain and also makes the whole setup quite brittle. I’ll write more about this in today’s post.
Best regatds, Igor
igorbrejc.net » Brainstorming: Distributed Continuous Integration System on 14 Jan 2009 at 19:34 #
[...] is the second part of my brainstorming "session" about automating software deployment and execution on a remote computer from yesterday. I did some investigation and found a very useful resource (part of the Paul [...]