Welcome to Manicprogrammer Sign in | Join | Help

Enforcing the Build Agent in a Team Build

 

From time to time you may have a need to ensure that a specific team build only runs on a specific build agent. I can't recall but I think that this is a forthcoming feature in the v.Next major release of TFS code named Rosario (I'll check to see if that is indeed a forthcoming feature). In Team Build 2008 there is not a ready mechanism to do so except with the blunt tool of being able to define build agents for a team project. So I'm going to throw you my little script that I use to evaluate the build agent at run time of the build script and have it fail if it is not authorized.

There is an easy enough means to do this if you want to evaluate to see if the build agent running the script matches a single allowed build agent name but if you get into saying that any 1 of 20 build agents can build a script you'll be a but more hard pressed to do so without a script like mine or a custom task. I try to avoid a custom task in these scenarios because it's just one more thing to need to be compiled on some occasion.  Oddly, in trying to avoid a custom task I ended up having to use MSBuild.Community.Tasks because I just could not get MSBuild to do exactly what I wanted.

Some may ask why you might only allow certain build agents to build certain scripts. A few reasons come to mind such as resource usage by the build, testing or network utilization such as large file copies. In my case I have some build servers that I'm having trouble with in automated creation of virtual directories and I want to ensure certain builds aren't even attempted on these machines until I resolve it.

If you only want to evaluate if a single build agent is running a script and error out if not then surely all you need is the following:

   1: <Target Name="BeforeEndToEndIteration" Condition="'$(BuildAgentName)'!='MYFAVORITEBUILDAGENT'"  >
   2:      <Error Text="This build can only be run on myfavoritebuildserver" />
   3: </Target>

But if you need to allow a script to run on 5 of 10 build agents setup for a team project then you will need something a bit more elaborate while still being easy to maintain and reuse. Obviously, each build script has a default build agent but nothing guarantees someone won't see a build already running on that agent and select another when queuing it up. And it may happen, based on the nature of the build, that I don't want a multi-hour full database deploy and system recompilation build running on the machines I expect to run quick CI builds.

I'm a big fan of batching in MSBuild. My first thought was I want to have an item group I can easily add items representing build agent names into. This list will be used to determine if the build agent running the script is allowed to run the script. If the build agent's name appears in the item list then it's golden.

Perfect!

Guess what. I couldn't figure out how I could readily batch across the list and come out the other side with an indicator if the build agent was in the list. I knew I needed the following:

(pseudocode)

    • set a property indicating if build agent is authorized to false
    • for each authorized agent in the list see if it is the agent running the build
      • if so set the flag about authorized to true
    • when done with loop see if flag is now true
      • if not throw an error and end

Happliy: Ibrahim took up the gauntlent and showed me in this post how he did it in the manner in which I most wished to do it. Look at his post: http://www.sedodream.com/PermaLink,guid,096a2e3f-fcff-4715-8d00-73d8f2491a13.aspx Basically he did the same thing I tried and thought has failed but he did it on a property in the target versus the target itself. I'll have to check this out and see if I was crazy and I could do it against the target or if you can't do it on the target but you can a property. I suspect the former. I haven't tried his method yet but have no reason to believe it wouldn't work just as advertised. Thanks Ibrahim.  Here is the type of element we had in common but at a different point: hmm.... Condition="'%(ChiAuthorizedBuildAgent.identity)'=='$(BuildAgentName)'"

 

I tried batching across a target using the item list in the condition of the target and then setting the flag accordingly. Such as:

   1: <Target Name="DetermineIfAuthorizedBuildAgent" Condition="'%(ChiAuthorizedBuildAgent.identity)'=='$(BuildAgentName)'">
   2:     <PropertyGroup><ChiIsAnAuthorizedBuildAgent>true</ChiIsAnAuthorizedBuildAgent></PropertyGroup>
   3: </Target>

But the above is not allowed. It will tell you that you can't use an items metadata directly in the condition and must use a transform. Fair enough so I tried the following:

   1: <Target Name="DetermineIfAuthorizedBuildAgent" Condition="'@(ChiAuthorizedBuildAgent -> '%(identity)')'=='$(BuildAgentName)'">
   2:   <PropertyGroup><ChiIsAnAuthorizedBuildAgent>true</ChiIsAnAuthorizedBuildAgent></PropertyGroup>
   3: </Target>

That worked but not the results I expected. The result is a flattened list versus batching across the target calling it once for each item ChiAuthorizedBuildAgent and evaluating. So you get the evaluation of 'buildagent1;buildagent2'=='buildagent1' which, of course, evaluates to false.

I suspect there is a way to do this but every way I came up with really required the condition to be much more dynamic than I could readily make it be. So I decided I'd back up and punt a little bit and while I was out it see if I could eek out a bit more flexibility from the script. In the end here is what I came up with...

I used the MSBuild.Community.Tasks.RegexMatch task to match against all the items in my ChiAuthorizedBuildAgentList thus output a new list of items that matched my input regex expression. Then I just checked to see if the new list when flattened in a condition was empty. If so nothing matched and the build agent running the script is not an authorized build agent and thus throws an error. The beauty was it let easily build patterns of agent names so that if needed I could have all build agents starting with CI allowed and not have to list them all. Also it let me easily make it case in-sensitive so I didn't have to worry about that either. In the example I provide below I am using a pure match not case sensitive versus some other pattern match but you'll get the point.

So... if you know of an easier way I can do this without the external task import using an item group I'd love to hear it. I'm sure there is a way and I won't be surprised if there is a better or simpler way I have completely overlooked but I was pleased with the outcome with this. Hope it helps if you need it.

 

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" > 
   3:  
   4:   <!-- Import the regex task -->
   5:   <UsingTask AssemblyFile="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.dll" TaskName="MSBuild.Community.Tasks.RegexMatch"/>
   6:  
   7:  
   8:   <!-- Define the default value for if this is an authorized build agent -->
   9:   <PropertyGroup>
  10:     <ChiIsAnAuthorizedBuildAgent>false</ChiIsAnAuthorizedBuildAgent>
  11:   </PropertyGroup>
  12:  
  13:  
  14:   <!-- Create an item group of the authorized build agents -->
  15:   <ItemGroup>
  16:     <ChiAuthorizedBuildAgent Include="PLACEHOLDER_FOR_AUTHORIZED_AGENT_1" />
  17:     <ChiAuthorizedBuildAgent Include="PLACEHOLDER_FOR_AUTHORIZED_AGENT_2" />
  18:   </ItemGroup> 
  19:  
  20:   <PropertyGroup>
  21:     <BeforeEndToEndIterationDependsOn>
  22:       $(BeforeEndToEndIterationDependsOn);
  23:       GetMatchingBuildAgents;
  24:       DetermineIfAuthorizedBuildAgent;
  25:     </BeforeEndToEndIterationDependsOn>
  26:   </PropertyGroup> 
  27:  
  28:   <!-- Use regex expression task with a regex expression (in this instance declaring in the expression that it is not case sensitive) 
  29:        to generate a new list of any items in the ChiAuthorizedBuildAgent list that matches the build agent this is running under
  30:   -->
  31:   <Target Name="GetMatchingBuildAgents">
  32:     <RegexMatch Input="@(ChiAuthorizedBuildAgent)" Expression="(?i)$(BuildAgentName)">
  33:       <Output ItemName="MatchingBuildAgents" TaskParameter="Output" />
  34:     </RegexMatch>
  35:   </Target>
  36:  
  37:  
  38:   <!-- If the MatchingBuildAgents list is empty then this is not an authorized build agent -->
  39:   <Target Name="DetermineIfAuthorizedBuildAgent">
  40:     <PropertyGroup Condition="'@(MatchingBuildAgents -> '%(identity)')'!=''" >
  41:       <ChiIsAnAuthorizedBuildAgent>true</ChiIsAnAuthorizedBuildAgent>
  42:     </PropertyGroup>    
  43:   </Target>
  44:  
  45:  
  46:   <!-- If this is not an authorized build agent then throw an error -->
  47:   <Target Name="BeforeEndToEndIteration"  DependsOnTargets="$(BeforeEndToEndIterationDependsOn)">
  48:     <Error Text="This build can only be run on one of the following build agents: @(ChiAuthorizedBuildAgent)"  Condition="'$(ChiIsAnAuthorizedBuildAgent)'=='false'" />
  49:   </Target>
  50:  
  51:  
  52: </Project>
  53:  

 

 

 

 

Published Thursday, June 19, 2008 9:51 PM by michaelruminer

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

Friday, June 20, 2008 12:35 AM by Sayed Ibrahim Hashimi

# re: Enforcing the Build Agent in a Team Build

If I understand your problem correctly you can do this with plain old MSBuild. I just blogged about it at http://www.sedodream.com/PermaLink,guid,096a2e3f-fcff-4715-8d00-73d8f2491a13.aspx

Sayed Ibrahim Hashimi

www.sedodream.com

Tuesday, June 24, 2008 8:42 AM by Team System News

# VSTS Links - 06/24/2008

Grant Holliday on When does the VSTS Codename &quot;Rosario&quot; April CTP VPC Expire? Michael Ruminer...

Tuesday, June 24, 2008 8:18 PM by Jason Stangroome

# re: Enforcing the Build Agent in a Team Build

Hi,

I'd rather redirect the build to the correct agent than fail the build. Not sure how to do that yet though.

Regards,

--

Jason

Friday, June 27, 2008 11:25 PM by Sayed Ibrahim Hashimi

# re: Enforcing the Build Agent in a Team Build

I have made a about conditions on targets, which is related to this. You can see it at http://www.sedodream.com/PermaLink,guid,a3e0f4b1-5714-4491-9134-cce95b1d6e19.aspx">http://www.sedodream.com/PermaLink,guid,a3e0f4b1-5714-4491-9134-cce95b1d6e19.aspx

Sayed Ibrahim Hashimi

http://www.sedodream.com

Saturday, June 28, 2008 8:51 AM by if ( ! blogClogged )

# Learning Something New on MSBuild Targets and Conditions

I love learning something new. Especially something that goes against what I would have expected. Such


Enter the text you see in the image:

Leave a Comment

(required) 
required 
(required)