Peel me a Grape :: We make things work

We Make Things Work :: Blog

Capistrano is commonly used for rails deployments. Automated deployment is a very good thing. A while back I wanted to do something like that on windows for a .net project.

Pstools is a collection of command-line tools for windows from sysinternals . They provide unix-style process control for windows systems. There are a few tools that let you do things remotely on another windows machine (if you have permission).

So, what I wanted to do with a .net project was:

  • Build the project on the local machine (called BUILD, say and working in c:\dev\myapp)
  • Mount the project working folder as a network share on the webserver (called WEB)
  • Run a script on WEB to deploy the built artefacts (copy to local folders, create IIS virtual hosts etc.)
  • Unmount the share

This should all be triggered from the BUILD machine using pstools.

If you keep your build tools in source control and you do this, you find that it won’t work. By default, windows security policy won’t execute .net apps from a shared drive. So running nant from your working folder won’t work. You can, however, manipulate that security policy using the Caspol tool . (You could probably skip this Caspol step if NAnt was installed on the target server as it would have trust to execute from the local drive on that machine.)

This is a proof of concept, showing how to make this work. It hasn’t been used extensively – though might be a good starting point to implement something like this. Details Follow…

Preliminaries

The code for this article is here in subversion: https://please.peelmeagrape.net/svn/public/nant/remote/

Going to use nant macrodef library to set this up.

We also need the pstools library (just psexec actually). The EULA on the sysinternals tools seem to indicate that I can’t redistribute them. So I’ve put a little bit of nant in the build file to download them:

<if test="${not file::exists('tools/pstools/psexec.exe')}">
  <mkdir dir="tools/pstools"/>
  <get src="http://download.sysinternals.com/Files/PsTools.zip" dest="tools/pstools.zip"/>
  <unzip zipfile="tools/pstools.zip" todir="tools/pstools"/>
</if>

The first time you use one of the pstools you will have to accept the EULA. (Though you could then check the exe into your source control and it should work from then on).

We will create a remote-nant task that will execute a target within a buildfile on a remote host. This task has some parameters:

  • remote_host: the host to execute on
  • target: The NAnt target to execute
  • buildfile: The NAnt buildfile to use
  • basedir: the local working folder to make available to the remote server
  • drive_letter: what drive to map to on the remote server
  • share_id: appended to our share name to make it unique (in the case where you might have multiple projects deploying to the target server)
  • dotnetpath: the path of the .net framework on the remote server (used to execute caspol, which might not be on the path). This defaults to the path on the local machine, which should usually work.

You need system-level permissions to execute on the remote server – not sure exactly what is the most restrictive set that will work though. You might want to edit the macrodef and add username and password parameters also.

Setup

First, we need to share out the working folder. This needs cmd.exe, and should not fail on error (in case it’s already mapped):


        <exec program="cmd.exe" failonerror="false">
          <arg value="/c"/>
          <arg value="net share remotenant${share_id}=${path::get-full-path(basedir)}"/>
        </exec>

Then we alter the security policy on the target host to give ‘FullTrust’ to code originating on the drive we are mapping:


        <exec program="psexec.exe" basedir="${basedir}\tools\pstools" failonerror="true">
          <arg value="\\${remote_host}"/>
          <arg value="-s"/>
          <arg value="cmd.exe"/>
          <arg value="/c"/>
          <arg
              value="${dotnetpath}CasPol.exe -machine -f -ag All_Code -url file:///${drive_letter}:/* FullTrust -name remote_nant_${drive_letter}"/>
        </exec>

These two steps (sharing out the working folder and granting trust to the mapped drive on the target host) are wrapped up as the setup-remote-deploy task. The remove-remote-deploy tears down the network share, unmounts it on the remote server and removes the trust from the security policy.

Note: Yes, while the remote_nant is running, the security policy of the target server is relaxed.

Running the task on the remote host

To actually run the task, we use psexec to start a cmd.exe shell on the remote server. In this shell, we mount the shared drive, switch to that drive and execute nant in that shell.

<remote-nant target="hello_world" remote_host="${remote_host}"/>
The example, at https://please.peelmeagrape.net/svn/public/nant/remote/ in subversion, has a hello world example. If you type go in the remote folder, it will execute the hello_world task. It executes against the localhost by default, use:
go -D:remote_host=server
to specify the host (or edit the build file).

( Writing this up from a Dublin Coding Brunch! )

blog comments powered by Disqus