Friday, December 15, 2017

Automated Builds and Deployments using TFS 2017 Release Management

TFS Release Management (RM) is Microsoft’s answer for DevOps. It can help you build, deploy and test your applications targeting various platforms and environments. RM also has a mini workflow approval process baked in for release automation.

Since last few weeks, I have been working on web app deployment using Visual Studio and Team Foundation Server 2017. I developed a solution and curated a number of resources that may provide some value to you.

Environment Setup

The environment we have in place is TFS 2017 Update 1, SQL Server 2016, and Visual Studio 2017. All of them in a virtual environment.

Overview

Conceptually you are touching three areas of TFS – source control, build and release. Here I have followed the tokenization approach instead of config transformation. So instead of creating multiple config transformations per environment, I opted to parametrize the configuration. This tokenized config lives in TFS version control system. TFS build then kicks in and produces a single WebDeploy (tokenized) package which can be deployed to various environments. The build is environment agnostic. TFS release management deploys the package using WebDeploy after replacing environment values for the tokens. This whole process ensures that deployed binary is same across environments.

TFS-Azure connection setup

  1. Setup and configure an Azure Resource Manager (ARM) service endpoint in your TFS environment.
  2. Make sure you are a member of project's "Endpoint Creators" group (if not Project Collection Administrators).
  3. Make sure you are part of “UserAccessAdmin” group defined by Azure. You can read more here: https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal 
  4. Open TFS web access and select the project's dashboard. 
  5. Click the Gear icon and select "Services" from the drop-down menu 
  6. Click "New Service Endpoint" and select "Azure Resource Manager" from the drop-down
  7. Enter the details in the Service Endpoint dialog as generated by PowerShell script. Read more here https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authenticate-service-principal
  8. Make sure verification is successful. Click OK.

TFS Version control setup


Create a publish profile for your web app

  1. Right-click web project in Solution Explorer and select Publish
  2. Click "Create new profile"
  3. Select "IIS, FTP etc." and click OK
  4. Select "Web Deploy Package" as publish method. Enter "WebDeployPkg" or any meaningful name for Package location
  5. Leave Site name blank
  6. Click Next
  7. Select Release from Configuration
  8. Leave File Publish Options unchecked
  9. Select "Use this connection string at runtime" checkbox for all Databases connection strings with custom placeholder values. I have prefixed a double underscore to the connection string name and also suffixed the same with double underscore too. For instance, in my web.config I have a connection string as AuthContext which becomes “__AuthContextStr__”
  10. Click Save
  11. Rename "CustomProfile" (newly created as above) as "WebPackage-Release" or any meaningful name.

Create Parameters file for your web app

In order to parameterize configurations defined in web.config other than connection strings, you need to use Parameters.xml file. This should be named exactly the same and must be located at the root level of your web project. MSBuild uses this parameters file to expose parameters/tokens. Please note MSBuild doesn’t fill in those tokens, it is MSDeploy which does that job. 
Here is a sample parameter.xml file:


Also, you can set the Build action of this parameters.xml file to “None”. This is needed to avoid the “Parameters.xml” getting deployed with your web application.
To test your solution, right-click and publish the web project using the publish profile created above (WebPackage-Release). Open the SetParameters.xml file, you should see tokens for the appSettings and the connection strings. Also, if you look into the zip file and view the web.config file, you’ll see there are placeholders for the connection strings. WebDeploy will inject the correct values for your appSettings and connection strings at deploy time.

TFS Build Setup

  1. Create an empty TFS build definition.
  2. Select $/{TfsProject} from repository dropdown
  3. Select "Continuous integration" checkbox
  4. Select "{PoolName}" from queue list
  5. Click Create
  6. Build
    1. Nuget Restore
      1. Click "Add build step" > Package > Nuget Installer > Add. Click Close.
      2. Enter "{SolutionName}.sln" in Path to solution for packages.config field
      3. Select Restore from Installation type
      4. Edit task name as "Restore NuGet packages"
    2. Build
      1. Click "Add build step" > Build > MSBuild > Add. Click Close.
      2. Click … next to Project field and select $/{TfsProject}/Dev/{SolutionName}.sln
      3. Enter "/p:RunCodeAnalysis=true /p:DeployOnBuild=true /p:PublishProfile=Release /p:PackageLocation=$(build.artifactstagingdirectory)" in MSBuild arguments field
      4. Enter C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\MSBuild.exe for MSBuild location under Advanced.
      5. Edit task name as "Build solution"
    3. Publish to staging
      1. Click "Add build step" > Utility > Publish Build Artifacts > Add. Click Close.
      2. Enter $(build.artifactstagingdirectory) for Path to Publish field
      3. Enter drop for Artifact Name field
      4. Select "Server" from Artifact Type drop-down
      5. Edit task name as "Publish artifacts to staging"
    4. Publish to DFS
      1. Click "Add build step" > Utility > Publish Build Artifacts > Add. Click Close.
      2. Enter $(build.artifactstagingdirectory) for Path to Publish field
      3. Enter PublishedOutput for Artifact Name field
      4. Select "File share" from Artifact Type dropdown
      5. Enter \\{NetworkPath}\$(Build.DefinitionName)\$(Build.BuildNumber) in Path field
      6. Edit task name as "Publish artifacts to DFS build drop location"
    5. UpdateTfsBuildQuality
      1. Click "Add build step" > Utility > PowerShell (run a PowerShell script) > Add. Click Close.
      2. Select "File Path" from Type drop-down.
      3. Enter UpdateTfsBuildQuality-v2.0.ps1 for Script Path field
      4. Enter -BuildQuality 'ReadyForDeployment' for Arguments field.
      5. Edit task name as "UpdateTfsBuildQuality"
  7. Options
    1. Create Work Item on Failure
      1. Type: Bug
      2. Assign to requestor: selected
      3. Additional Fields
        1. System.Title: Build $(Build.BuildNumber) failed
        2. System.Reason: Build failure
  8. Repository
    1. Repository type: Team Foundation Version Control
    2. Repository name: {TfsProject}
    3. Label sources: On successful build
    4. Label format: $(build.buildNumber)
    5. Clean: true
    6. Clean options: All build directories
    7. Mappings
      1. Map: $/{TfsProject}/Dev with Local Path:$(build.sourcesDirectory)\
  9. Variables
  10. system.debug false
    BuildConfiguration Release
    BuildPlatform any CPU
    BuildDropLocation \\{DFS}\$(ProductCode)\$(Build.DefinitionName)\$(Build.BuildNumber)
    SharedDeploymentResourcesLocation \\{DFSPath}\ReleaseManagement
  11. Triggers
    1. Select Continuous Integration
    2. Select Batch changes
    3. Path Filters: Include $/{TfsProject}/Dev
  12. General
    1. Default agent queue: {PoolName}
    2. Build job authorization scope: Current Project
    3. Description: Dev Continuous Integration Build
    4. Build number format: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr)
    5. Build job timeout in minutes: 10
    6. Badge enabled: selected
    7. Demands
      1. BuildType Equals CI
      2. AgentType Equals BuildOnly
  13. Retention
    1. Days to keep: 15
    2. Min to keep: 3
    3. Delete build record: selected
    4. Delete source label: unchecked
    5. Delete file share: selected
    6. Delete symbols: selected
    7. Delete test results: selected
Run the build. When complete, the build drop should contain the site zip and SetParameters.xml file as well as some other files.

TFS Release Setup

  1. You need to install some extensions from the Marketplace before deploying release.
    1. Package Management [https://marketplace.visualstudio.com/items?itemName=ms.feed]
    2. Release Management Utility tasks [https://marketplace.visualstudio.com/items?itemName=ms-devlabs.utilitytasks]
  2. Ensure AzureRM PowerShell module is installed on release agent machine. If not, follow these instructions https://docs.microsoft.com/en-us/powershell/azure/install-azurerm-ps?view=azurermps-5.0.0
  3. Make sure service account doing releases has read-write permissions on build drop location.
  4. Provision release service accounts with the following project and build permissions:
    1. Project Permissions:
      1. View project-level information
      2. View test runs
    2. Build (All) permissions:
      1. Edit build quality
      2. Retain indefinitely
      3. View build definition
      4. View builds
  5. Create an agent queue for the release environment that has an agent that can reach the Azure server.
  6. Create a basic Team Release using the empty template 
  7. Environment
    1. Rename "Environment 1" to "DEV"
    2. Transform Tokenized Parameters File
      1. Click "Add task" > Utility > Tokenize with Xpath/Regular expressions > Add. Click Close.
      2. Enter "$(TfsBuildDropLocation)\$(ProductCode)\$(Build.DefinitionName)\$(Build.BuildNumber)\$(TfsBuildPublishFolder)\{ProjectName}.SetParameters.xml" for Source filename
      3. Enter "$(TfsBuildDropLocation)\$(ProductCode)\$(Build.DefinitionName)\$(Build.BuildNumber)\$(TfsBuildPublishFolder)\{ProjectName}.SetParameters.DEV.xml" for Destination filename
      4. Edit task name as "TransformTokenizedParametersFile"
    3. Deploy to Azure Web App
      1. Click "Add task" > Deploy > Azure App Service Deploy > Add. Click Close.
      2. Select "{AzrSubscription}" from Azure Subscription dropdown
      3. Select "{AzrWebAppName}" from App Service name dropdown
      4. Click "Deploy to slot"
      5. Select "{AzrResourceGroup}" where web app belongs from Resource group dropdown
      6. Select "dev" from Slot dropdown
      7. Enter "$(TfsBuildDropLocation)\$(ProductCode)\$(Build.DefinitionName)\$(Build.BuildNumber)\$(TfsBuildPublishFolder)\**\*.zip" for Package or Folder field
      8. Click "Publish using Web Deploy"
      9. Enter "$(TfsBuildDropLocation)\$(ProductCode)\$(Build.DefinitionName)\$(Build.BuildNumber)\$(TfsBuildPublishFolder)\ )\{ProjectName}.SetParameters.DEV.xml" for SetParameters File field
      10. Enter "-verbose -allowUntrusted" for Additional Arguments field
      11. Edit task name as "DeployToAzureAppServiceSlot"
    4. Delete Transformed Parameters File
      1. Click "Add task" > Utility > Delete files > Add. Click Close.
      2. Enter "$(TfsBuildDropLocation)\$(ProductCode)\$(Build.DefinitionName)\$(Build.BuildNumber)\$(TfsBuildPublishFolder)" for Source Folder field
      3. Enter "*.SetParameters.DEV.xml" for Contents field
      4. Click Always run
      5. Edit task name as "DeleteTransformedParametersFile"
    5. Set Tags for deployed slot
      1. Click "Add task" > Deploy > Azure PowerShell > Add. Click Close.
      2. Select "Azure Resource Manager" for Azure Connection type
      3. Select "{AzrSubscription}" for Azure RM Subscription
      4. Select "Script File Path" for Script Type
      5. Enter "\\DFSPath\SetAzureWebAppTags-v1.0.ps1" for Script Path
      6. Enter "-AzWebAppSlot 'DEV' -AzWebApp '{webappname}' -AzResourceGroup '{AzrResourceGroup}'" for Script Arguments
      7. Edit task name as "SetTagsForDeployedSlot"
    6. UpdateTfsBuildQuality
      1. Click "Add build step" > Utility > PowerShell (run a PowerShell script) > Add. Click Close.
      2. Select "File Path" from Type drop-down.
      3. Enter \\DFSpath\UpdateTfsBuildQuality-v2.0.ps1 for Script Path field
      4. Enter -BuildQuality 'Released' for Arguments field.
      5. Edit task name as "UpdateTfsBuildQuality"
  8. Variables
    1. Add variables as defined below
    2. TfsBuildDropLocation \\DFS\Builds
      ProductCode ABCD
      TfsBuildPublishFolder PublishedOutput
      SharedDeploymentResourcesLocation \\DFS\Builds\tfs\ReleaseManagement
  9. General
    1. Enter "$(Release.DefinitionName)_$(Date:yyyyMMdd)$(rev:.rr)" for Release name format
  10. Retention
    1. Days to retain a release: 15
    2. Min releases to keep: 3
  11. Click … next to DEV environment and select "Configure Variables" option from the context menu. Define variables as:
    1. AuthContextStr Data Source=inst.database.secure.windows.net; database=db;user id=sa;password={pwd};
      Environment DEVELOPMENT
      MachineKey-ValidationKey {key}
      MachineKey-DecryptionKey {key}
These variable values will be injected. For instance, “Environment” and then tokenized connection string with tokens for the server, database, user, and password. These values will be used by the “TransformTokenizedParametersFile” task to inject into the SetParameters file in the placeholders. When WebDeploy runs, it replaces placeholder values in the web.config (in the package zip) file with the values that are in the SetParameters.xml file. 

There are more powerful and valid use cases out there that you can explore. However, for my scenario, the above solution worked like a charm.

Hope this helps.

References: 

Wednesday, April 26, 2017

TFS 2017 – Upgrade from TFS 2015

Current scenario: TFS 2015 Update 2 (Application Tier) on Windows 2012 R2. SQL Server 2012 (Data Tier) on Windows 2012 R2. Two TFS Build servers on Windows 2012 R2. SharePoint 2013 on Windows 2012 R2. Reporting Services configured on AT as well.

New Scenario: Upgrade AT with 2017 Update 1 on the same hardware. New hardware for SQL 2016 SP1 (DT). In-place upgrade for Build servers with TFS 2015 Update 3. Also, in-place upgrade of TFS extensions on all SPS WFEs.

So to summarize, we need to migrate current DT to new proposed 2016 DT (Since TFS 2017 requires SQL 2014 or above). And everything else will be the in-place upgrade.

There were a couple of snags which I had initially hence I need to re-run the whole process in the Test environment to gain some confidence before Production move. I’m grateful that we have virtualized servers.

I have put the whole process in step by step list for anyone interested.

1.     Pre-deployment Plan

Step
Details
PRE01      
Database backups

Request the full backups of TFS databases running on Data Tier (DT). Make sure backups of databases from Database and Analysis engine both are made.
PRE02      
Server Snapshots

Request snapshots of all servers including Application Tier (AT) and build servers.
PRE03      
Free space availability

·         Make sure you have 50 gigs of free space in E: drive on AT for cache.
·         Make sure you have enough space in C: drive on AT for 2017 install.
·         Make sure you have enough space in E: and F: drive on new 2016 DT for DB restore operation.
PRE04      
Install Team Foundation Server extensions for SharePoint Products onto a remote installation of SharePoint Products

SPS needs to be updated with TFS 2017 extensions before you can configure TFS on AT.
PRE05      
Ensure Services are running

1.       Make sure “Remote Access Connection Manager” service is running and startup type is Automatic on all Build Servers. (Ensure one of the dependent services “Telephony” is also running and startup type should be Automatic.)
PRE06      
New SQL 2016 server for TFS

1.       Setup a new SQL 2016 server for hosting TFS databases, analysis services and SSRS.
2.       Configure DNS aliases if required.
3.       Migrate existing security logins from current SQL 2012 onto new SQL 2016.
4.       Make sure SP1 is installed for SQL and SSRS 2016
5.       Make sure you have the full-text search feature installed on new 2016 DT. This feature is required for Team Foundation Server to operate correctly. Verify here.
PRE07      
Configure new SQL 2016 server for TFS

On 2016 DT:
1.       Add “TFSSERVICE” to
a.       “Log on as a service” permission.
b.       “Content Manager” role on the SQL Server Reporting Services.
c.       “TFSExecRole”, or if this role does not exist in the database, a combination of the following roles for any databases that Team Foundation Server uses:
                                                               i.      db_owner
                                                             ii.      db_create
2.       Add “TFSREPORTS” to
a.       “Allow Log on locally” permission on Application Tier, Data Tier and Build servers.
b. "TFSWareHouseDataReader" permission on the report server.
3.       Add “TFSINSTALL” as:
a.       Local admin
b.       SA role on databases and Analysis services

2.     Deployment Plan

Step
Details
DEP01      
Stop IIS and TFS Services.

On AT login as TFSInstall service account and follow the steps below.

Execute following statement from an elevated command prompt:

"C:\Program Files\Microsoft Team Foundation Server 14.0\Tools\TfsServiceControl.exe" quiesce

Note: If the above statement fails, manually stop IIS App pools and sites.
DEP02      
Apply Update 3 to TFS 2015 server

On AT login as TFSInstall service account and follow the steps below.


Launch TfsServer2015.3.exe to begin the installation:



  










  
DEP03      
Start IIS and TFS Services.

On AT login as TFSInstall service account and follow the steps below.

Execute following statement from an elevated command prompt:

"C:\Program Files\Microsoft Team Foundation Server 14.0\Tools\TfsServiceControl.exe" unquiesce

Note: If the above statement fails, manually start IIS App pools and sites.
DEP04      
Install Team Foundation Build Service

Follow the below-mentioned steps on all the build servers.

On Build server login as TFSInstall service account and follow the steps below.

Launch TfsServer2015.3.exe to begin the installation:

1.       Choose the default location, and then click Install. The TFS Upgrade wizard appears.
2.       On TFS Configuration Center screen, chose Configure XAML Build Service and click Start Wizard
3.       On the Welcome screen, click Next.

Chose Yes on Use Existing resources confirmation.
4.       Make sure the concerned collection appears on the following screen.

5.       Specify credentials for TFSService account. Under Run Team Foundation Build Service as, make the following selection, and then click Next:
a.       Choose Use a user account, and then enter the account name (TFSSERVICE) and password.
b.       Click Test. Make sure it succeeds.

6.       Click Next
7.       Click Next on Review screen.
8.       Click Configure

Restart build controller after the upgrade is successful.
DEP05      
Backup TFS SQL 2012

1.       Stop IIS (follow DEP01 above).
2.       Execute following command from elevated command prompt:

“C:\Program Files\Microsoft Team Foundation Server 15.0\Tools\TfsBackup.exe”

Select Old DT as source sql server instance.
Enter network path for backup database location.

DEP06      
Backup SSRS encryption key

On AT login as TFSInstall service account and follow the steps below:

1.       Launch Reporting Services Configuration Manager
2.       Connect to MSSQLServer.
3.       Select Encryption keys from the left pane and click Backup.
4.       Enter file location and password
5.       Confirm the presence of key under specified location as in #4.
DEP07      
Restore SQL 2012 databases onto SQL 2016 instance

On new DT login as TFSInstall service account and follow the steps below:

1.       Detach ReportServerDB and ReportServerTempDB.

On AT login as TFSInstall service account and follow the steps below:

1.       Execute following command from elevated command prompt:

“C:\Program Files\Microsoft Team Foundation Server 15.0\Tools\TfsRestore.exe”

SelectNew DT as target SQL server instance.
Enter network path for backup database location.

Ask DBAs to restore Tfs_Analysis DB from old DT to New DT. Use backups as specified in Pre-deployment step PRE01.
DEP08      
Restore SSRS encryption key

On new DT login as TFSInstall service account and follow the steps below:

1.       Launch Reporting Services Configuration Manager
2.       Select Encryption keys from left pane and click Restore.
3.       Refer backup
4.       If Scale-out deployment shows old and new SSRS instances both, delete old one.
a.       rskeymgmt –l
b.       rskeymgmt -r [remove old one]

DEP09      
Remap and configure TFS 2015.3 for new SQL 2016 server

On new AT login as TFSInstall service account and follow the steps below:

1.       Open an elevated command prompt.
2.       Set pwd to “C:\Program Files\Microsoft Team Foundation Server 14.0\Tools”
3.       Execute:

TfsConfig.exe RemapDBs /DatabaseName:;Tfs_Configuration /SQLInstances: /AnalysisInstance:< NewDTServer > /AnalysisDatabaseName:Tfs_Analysis

TfsConfig.exe Accounts /Add /AccountType:ApplicationTier /Account: /Password: /SqlInstance: < NewDTServer > /DatabaseName:Tfs_Configuration

TfsConfig.exe Accounts /Add /AccountType:ReportingDataSource /Account: /Password: /SqlInstance:< NewDTServer > /DatabaseName:Tfs_Configuration

[Close Console if its open]
TfsConfig.exe RegisterDB /SqlInstance:< NewDTServer > /databaseName:Tfs_Configuration

4.       Open TFS Administration Console

·         Select Reporting tab and click Edit.
·         Click OK to stop jobs.
·         Verify and Update the new settings. Under Reporting tab enter new “NewDTServer” as the server. May need to re-enter creds.
·         Start Jobs.
DEP10      
Restart TFS

Restart services on AT.

DEP11      
Update connection for OLAP data source

Open browser (with TfsService account) with Url as http://< NewDTServer >/Reports/manage/catalogitem/properties/Tfs2010OlapReportDS

Under connection string update Data Source with “NewDTServer”.
Supply the password for Report Reader account (TFSREPORTS).
Test connection. If success, click Apply.
DEP12      
Upgrade Team Foundation Server 2017 Update 1

On AT login as TFSInstall service account and follow the steps below.

1.       Stop AT
2.       Mount following iso and launch Tfs2017.1 to begin the installation:
3.       After successful completion, if prompted to restart, agree.
4.       TFS Configuration Center window will pop up after reboot.

5.       In the Team Foundation Server Configuration wizard (Welcome screen), choose No, I do not want to participate, and then click Next.
6.       Choose the second option of “I have existing databases to use for this TFS deployment” and click Next 




7.      
8.       Select “Production Upgrade” and click Next
9.       Specify credentials for TFSservice account and ensure Test pass.
10.  
11.   Don’t install or configure Search feature at this time. Click Next
12.   Click “Configure Reporting for use with TFS”. Click Next
13.   For reporting services instance enter “ReportServerAlias”





14.   Select “Enable integration with SharePoint”
15.   Verify and confirm.
16.   Click Configure, Next
17.   Save the logs.
18.   Click Close
19.   Revert authentication protocol to NTLM (optional)

Execute following command from an elevated command prompt:

“C:\Program Files\Microsoft Team Foundation Server 15.0\Tools\TFSConfig.exe Authentication /provider:NTLM /siteType: ApplicationTier”
DEP13      
Restart TFS Build Controllers

Follow the below-mentioned steps on both the build servers.

On Build server login as TFSInstall service account and follow the steps below.

1.       Open TFS Administration Console.
2.       Select XAML Build Configuration
3.       Restart controller
DEP14      
Update SSRS data source

Follow here (DEP011)
      

3.     Post-deployment Plan


Step
Details
PST01 
Provision TFS Service account

Make sure following roles exists under Tfs_Analysis SSAS database called:
a.        TfsWarwhouseDataReader:  (members=TFSREPORTS, SPSFarmAdmin) with none permissions
b.       TfsWarehouseAdministrator: with full control and members TFSSERVICE, TFSINSTALL

PST02 
Configure Security and new Features in TFS 2017.1

·         Enable the “New Work Item“ form.
Go to collection admin page. Click “Enable the new work item form”.
Click “Configure the opt-in model” and select “Enable opt-in for all users”.


PST03 
Repair SharePoint connection

On AT server login as TFSInstall service account and follow the steps below.

Open TFS Admin console.
Select SharePoint Web Applications and click Repair Connection.

Note: If SharePoint portal widgets throw an error about TFS project not found then either wait for TFS sync jobs to finish (24 hrs.) or clear cache on all SPS WFE and TFS AT. Cache is located under “C:\ProgramData\Microsoft\Team Foundation\Web Access”.

Reset IIS on all WFEs.
PST04 
Deprovision old TFS databases

Request de-provision of old TFS databases on old DT.