Programmatically use a server as the Build Server for multiple Project Collections

Posted on Ewald Hofman See other posts from Ewald Hofman
Published on Thu, 25 Nov 2010 14:41:13 +0100 Indexed on 2010/12/29 18:00 UTC
Read the original article Hit count: 757

Filed under:
|
|

Important: With this post you create an unsupported scenario by Microsoft. It will break your support for this server with Microsoft. So handle with care.

I am the administrator an a TFS environment with a lot of Project Collections. In the supported configuration of Microsoft 2010 you need one Build Controller per Project Collection, and it is not supported to have multiple Build Controllers installed. Jim Lamb created a post how you can modify your system to change this behaviour. But since I have so many Project Collections, I automated this with the API of TFS.

When you install a new build server via the UI, you do the following steps

  1. Register the build service (with this you hook the windows server into the build server environment)
  2. Add a new build controller
  3. Add a new build agent

So in pseudo code, the code would look like

foreach (projectCollection in GetAllProjectCollections)
{
      CreateNewWindowsService();
      RegisterService();
      AddNewController();
      AddNewAgent();
}

The following code fragements show you the most important parts of the method implementations. Attached is the full project.

CreateNewWindowsService

We create a new windows service with the SC command via the Diagnostics.Process class:

            var pi = new ProcessStartInfo("sc.exe")
                         {
                             Arguments =
                                
string
.Format(
                                    
"create \"{0}\" start= auto binpath= \"C:\\Program Files\\Microsoft Team Foundation Server 2010\\Tools\\TfsBuildServiceHost.exe
             /NamedInstance:{0}\" DisplayName= \"Visual Studio Team Foundation Build Service Host ({1})\""
,
                                     serviceHostName, tpcName)
                         };
           
Process
.Start(pi);

            pi.Arguments =
string.Format("failure {0} reset= 86400 actions= restart/60000"
, serviceHostName);
           
Process.Start(pi);

RegisterService

The trick in this method is that we set the NamedInstance static property. This property is Internal, so we need to set it through reflection. To get information on these you need nice Microsoft friends and the .Net reflectorSmile .

            // Indicate which build service host instance we are using
            typeof(BuildServiceHostUtilities).Assembly.GetType("Microsoft.TeamFoundation.Build.Config.BuildServiceHostProcess").InvokeMember("NamedInstance",
             System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.Static, null, null, new object[] { serviceName });

           
// Create the build service host
            serviceHost = buildServer.CreateBuildServiceHost(serviceName, endPoint);
            serviceHost.Save();

           
// Register the build service host
            BuildServiceHostUtilities
.Register(serviceHost, user, password);

AddNewController and AddNewAgent

Once you have the BuildServerHost, the rest is pretty straightforward. There are methods on the BuildServerHost to modify the controllers and the agents

                controller = serviceHost.CreateBuildController(controllerName);
                agent = controller.ServiceHost.CreateBuildAgent(agentName, buildDirectory, controller);
                controller.AddBuildAgent(agent);
You have now seen the highlights of the application. If you need it and want to have sample information when you work in this area, download the app
TFS2010_RegisterBuildServerToTPCs


© Ewald Hofman or respective owner

Related posts about TFS SDK

Related posts about VSTS 2010