Creating a Team City 9 server on a Windows Azure VM

As part of the crane open source project that I talked about in this post, I am setting up a Team City Server in Azure.

I ran into a few problems so I wanted to document the process from start to finish here:

 

  1. Create a new VM on azure using the Azure management portal selecting a Windows Server 2012 R2 machine
  2. Click on “all items” on the left, select the new virtual machine then click ‘connect’ in the bar at the bottom.  This will download an rdp file configured to remote in to the desktop.
  3. Log in to the new vm using the username and password you setup in step 1
  4. At this point I wanted to download and install Team City but I had real trouble getting Team City to download in IE.  I then tried to download Chrome and I could not get Chrome to download either.  So I ended up installing chocolately and then installing Chrome through chocolatey.  If anyone reading this knows a better way please let me know.
  5. Open powershell as admin
  6. Run the command “Set-ExecutionPolicy Unrestricted”
  7. Run the command “iex ((new-object net.webclient).DownloadString(‘https://chocolatey.org/install.ps1‘))”
  8. Chocolately should now be installed.  Next we need to install Chrome using chocolatey.  Run the command “choco install GoogleChrome”
  9. Open up google chrome and download the Team City 9 EAP (or whichever version of Team City you want to run)
  10. Run the Team City installer, for ease I would use port 80 for the port.  Select the local system account both for the team city server and agent service
  11. Team City should now be up and running, feel free to configure your builds using crane 🙂
  12. Now at this point I thought (naively) that it would all just work but that’s not the case.  You need to setup some firewall rules to allow traffic through
  13. Open server manager (by default its the first item in the task bar with the picture of the suitcase)
  14. Click “Tools > Windows firewall with advanced security” to open up the firewall rules window
  15. Select “inbound rules” then “add new rule”, this will open up the new rule wizard.
  16. Select “port” as the rule type, click next.
  17. Type 80 in the port box (or whichever port you used for Team City), click next
  18. Click “allow the connection”, click next
  19. Leave the profile as is, click next
  20. Then click next on the last screen
  21. Now we have configured Windows Server to allow the connection, now we just have to open up the load balancer in azure…
  22. Go back to the azure management portal
  23. Click on all items on the left and select your virtual machine
  24. Select endpoints at the top
  25. Click add at the bottom
  26. Select add a “stand alone endpoint” click next
  27. If you have used port 80 then you can simply select “http” from the drop down list and click next.  If you have used a custom Team City port then you will need to set up the private port to the port you put Team City on and the public port to the port you want to use on the internet.  For example if you put Team City on port 8000 but you want to access it on port 80 you would select port 8000 for the private port and 80 for the public port.  Click next.
  28. Once Azure finishes updating you should now be able to access your Team City server on the internet by going to <vmname>.cloudapp.net

I hope you found this helpful and it has saved you some time.  I don’t think a lot of that is obvious out of the box.

Crane – Building you into the pit of success

I have recently started an open source project with a colleague (Ed Wilde). The project is called crane check it out on github. The idea behind the project is to write a tool that creates .Net builds for you automatically. For those of you who have spent time on a build server like Team City (not to pick on Team City as all build servers suffer from this) it takes quite a bit of time just to set up a boiler plate build.

A lot of that time is spent configuring the steps of the build normally something along the lines of the following:

  1. Get latest source
  2. Updated assembly build versions
  3. Build software
  4. Run tests
  5. Pack into nuget
  6. Publish into nuget

It can be confusing even for a developer with experience to set the build up in the right way and not only that but in a way that scales well as more applications are built.

This is where crane comes in.  The idea is you can point crane at your solution and it will generate you a build automatically with all of the steps in place.  By convention.  We believe we can use our experience of configuring builds to give you a great starting place either for a brand new project or to create a build for an existing project.

We are also planning to give crane the ability to create build chains by analysing your solutions.  This will give you the ability to split up your code base and work on smaller projects without the headache of trying to build it.

We would love to hear your initial thoughts on crane and whether it would be a useful tool for you.

 

Handy powershell script for deploying nuget packages

I was recently presented with the problem to automate the deployment of a nuget package to a server. Now before you guys say I know that Octopus Deploy is the best way to go and I completely agree. At the moment at the organisation I’m at using a product like Octopus has to go through an “approval” process. Faced between the choice of having to carrying on deploying using file explorer (which is what the guys currently did here) and automating it, I voted for the latter option.

Now Team City is not really geared towards doing deployments. After all it’s designed to be a build server and that’s what it does extremely well. However we can make it work.

The first thing you need to do is package up your built web site into a nuget package and deploy it to a nuget server (either a local one or the public one). For those that dont know a nuget package is literally a zip file, you can even rename it .zip and it will extract. The reason for using a nuget package is that it gives you a nice way to place it onto a server, version it and in the future plug in Octopus Deploy.

So onto the script:


param([string]$computerName, [string]$destinationDir, [string]$packName, [string]$packVersion, [string]$executeLocally)

Write-Host "computer name: $computerName"
Write-Host "destination dir: $destinationDir"
Write-Host "package name: $packName"
Write-Host "package version: $packVersion"
Write-Host "execute locally: $executeLocally"

$deployScript = {
param($dest, $packageName, $version)

$basePath = "d:\packages\"

$packageNameAndVersion = "$packageName.$version"
$extractDir = $basePath + $packageNameAndVersion

Write-Host "deploying to: $dest"
Write-Host "extracting to: $extractDir"
Write-Host "package: $packageName"
Write-Host "version: $version"

$zipDownload = $packageNameAndVersion + ".zip"

$packageUrl = "http://nuget.org/api/v2/package/$packageName/$version"

if (-Not (Test-Path $extractDir))
{
New-Item -ItemType directory -Path $extractDir
}else{
Get-ChildItem -Path ($extractDir + "\*") -Recurse | Remove-Item -Recurse -Force -Confirm:$false
}

$Path = $basePath + $zipDownload

Write-Host "Downloading package..."
$WebClient = New-Object System.Net.WebClient
$WebClient.DownloadFile($packageUrl, $path )

Write-Host "Extracting package..."

$shell = new-object -com shell.application
$zip = $shell.NameSpace($path)

foreach($item in $zip.items())
{
$shell.Namespace($extractDir).Copyhere($item)
}

Write-Host "Cleaning destination..."

Get-ChildItem -Path $dest -Recurse | Remove-Item -Recurse -Force -Confirm:$false

Write-Host "Deploying..."

Copy-Item ($extractDir + "\*") $dest -Recurse

Write-Host "Removing downloaded package from $path"
Remove-Item $path -Recurse -Force -Confirm:$false

Write-Host "Removing extracted package from $extractDir"
Remove-Item $extractDir -Recurse -Force -Confirm:$false
Remove-Item ("$extractDir\") -Recurse -Force -Confirm:$false

Write-Host "Done."

}

$output = Invoke-Command -ScriptBlock $deployScript -ArgumentList $destinationDir, $packName, $packVersion

Now when you configure your team city build you need to pass in the following 3 parameters: $destinationDir, $packName and $packVersion. The destination dir is the directory you wish to deploy to e.g. \\192.168.1.1\WebSites\MyWebSite. The package name is the package id of the nuget package and the packVersion is the version number of the nuget package. That’s it! Simply huh?

You will need to make sure that the Team City user account has write access to the folder you are deploying to.

deploy

In the screenshot above you can see how to setup the powershell script to run. You can either check it into your source control system and then enter the path to the file in the script file dialog above or alternatively you can copy and paste the source directly into Team City. I would recommend having the powershell script in source control as then if you have multiple deploy builds changing the script will mean every build will get the new powershell script.

In the script arguments dialog you need to pass in the parameters to the script described above.  You can either hard code these (not recommended) or you can use Team City parameters and then present the user with a dialog when they go to run the build.  To do this I use the following parameters:

%website-deployment-dir% %package-name-to-deploy% %package-version-to-deploy%

After you have saved this, Team City will prompt you to setup these parameters. Go to the parameters section of your build configuration. Click on one of the parameters. Click spec, then in the dialog that appears next to display select “prompt”. You can enter a default value if you wish or even give the user a dropdown select with for example every website they can deploy. By using the prompt option when the user clicks to run the build they will be presented with a dialog that will force them to enter these parameters.

So there you have it, a quick and simple build that can deploy any nuget package to any server. Simples.

As always if anyone has any questions or wants to go through anything feel free to contact me. Happy deployments!