Supporting Multiple Environments in a single TeamCity Build Config

Having multiple build configs can clutter up the TeamCity dashboard and make maintenance bothersome. The use of inheritance and build templates can help with maintenance, but that doesn’t solve the issue of having a build config for each environment (DEV, TEST, PROD, etc).

Using TeamCity service messages and the TeamCity REST API can help solve this problem and keep all operations for a project under one build config. In some cases this can help reduce costs since the number of build configs TeamCity allows is limited by the Licensing that was obtained.

The example used in this article is to support deployment to multiple environments however this may be used for builds, testing and so on.

By following this article, the TeamCity dashboard would go from looking like this (with a “Execute Deployment” build config under each project):

Before

To this:

After

Selecting an environment will now occur when clicking “Run” on the new build config; the user will be prompted to select an environment.

Procedure

  1. For this to work correctly all values that need to change per environment must be parameterized. You should also consider making a TeamCity service account that will be used for REST API calls.
  2. Devise a parameter naming convention to denote the environment that the parameter value belongs to. Avoid using prefixes that interfere with TeamCity’s defaults (env., system., dep.)
    1. Ex:
      TargetServerAddress becomes defined as:
      DEV.TargetServerAddres
      TEST.TargetServerAddress
      PROD.TargetServerAddress
  3. Go through all the parameters and update them to follow the formatting specified above.
  4. On the TeamCity project that will have the environment switches, add a parameter “TargetEnvironment” which will prompt the user for a selection upon running a build.
    1. Select “Edit…” in the Spec section to modify the parameter to prompt the user
    2. Fill in the various environment identifiers (these are defined in step 2)
    3. The final result should look like this
  5. Create a build config to execute a shell script. The following examples are done using the PowerShell build runner.
    1. Create your auth headers.
      $pair = "$($TeamCityApiUserName):$($TeamCityApiPassword)"
      $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
      $basicAuthValue = "Basic $encodedCreds"
      $tcHeaders = @{
      "Authorization" = $basicAuthValue;
      "Accept" = "application/xml";
      "Content-Type" = "application/xml";
      }
    2. Create helper function to get all TeamCity parameters for a specified Project Id.
      Function GetTeamCityParameters($ProjectId) {
      try {
      $api = "$($TeamCityHost)httpAuth/app/rest/projects/id:$ProjectId/parameters"
      $response = Invoke-WebRequest -Uri $api -Headers $tcHeaders -Method GET
      $api
      return ( $response).properties.property
      } catch {
      throw
      }
      }
      
    3. Create  helper function to Emit TeamCityParameters using TeamCity Service Messages
      Function EmitTeamCityParameter($Key, $Value) {
      Write-Host "##teamcity[setParameter name='$Key' value='$Value']"
      }
    4. Loop through all matching parameters to emit the value of “DEV.TargetServerAddress” as the value for “TargetServerAddress”.
      ForEach ($param in (GetTeamCityParameters $ProjectId)) {
      if ($param.Name -and $param.Name.StartsWith("$TargetEnvironment.")) {
      EmitTeamCityParameter -Key ($param.Name).Replace("$TargetEnvironment.","") -Value "%%$($param.Name)%%"
      }
      }
  6. To make use of these freshly emitted environment parameters whichever build config being set up for multi-environment use, in my case Execute Deployment, must have a Snapshot Dependency on the build config that emits the environment parameters.
    1. Every time an emitted parameter is to be used it must be called on via dependency parameter. For instance, to use the emitted value “TargetServerAddress” in a build config it must be called like so:
      %dep.EmitEnvironmentParameters.TargetServerAddress%
    2. This is because using TeamCity Service Messages will only update the value of the parameter for the single build that executed. What this means is after Emit Environment Parameter executes, the value of “TargetServerAddress” never gets persisted.

 

You may run into problems when attempting this password parameters. This is because TeamCity masks all passwords as asterisks before executing the script, effectively resulting in the parameter value being updated as ******* rather than whatever the passwords true value is. In the next blog post, we will discuss using the TeamCity REST API to get around this issue with passwords.

Securing an ASP.NET Core App on Ubuntu Using Nginx and Docker (Part I)

Typically, when you develop with ASP.NET you have the luxury of IIS Express taking care of SSL and hosting, however IIS and IIS Express are exclusive to the Windows platform. ASP.NET Core 1.0 has decoupled the web server from the environment that hosts the application. This is great news for cross-platform developers since web servers other than IIS such as Apache and Nginx may be set up on Linux and Mac machines. Securing ASP.NET Core App on Ubuntu Using Nginx and Docker Part 1.png

This tutorial involves using Nginx as the web server to host a dockerized .NET Core web application with SSL Termination on a Ubuntu machine. In this three-part tutorial, I’ll guide you in:

Part I (This post)  1. Creating and publishing an ASP.NET Core web app using the new dotnet CLI tools and 2. Installing and configuring PuTTY so we may SSH and transfer files with our Ubuntu machine

Part II – Setting up Docker and creating a Docker Image on Ubuntu 16.04

Part III – 1. Configuring Nginx for SSL termination and 2. Building and Running the Docker Image.

Continue reading “Securing an ASP.NET Core App on Ubuntu Using Nginx and Docker (Part I)”