Windows Azure Web Site
This is a Deployment Manager Deploy.ps1 PowerShell script to deploy a Windows Azure Web Site.
To use it, you will need to both add some variables in DM, as well as having configured the machine where the DM agent runs, in the user account that the DM agent run as, to have your credentials to the Windows Azure Web Site so that it can stop + start the website.
In more detail, the variables are:
* Add git to %PATH%
* Get-AzurePublishSettingsFile
* Import-AzurePublishSettingsFile <filename>
Then you'll need this in a Deploy.ps1 file in your package:
To use it, you will need to both add some variables in DM, as well as having configured the machine where the DM agent runs, in the user account that the DM agent run as, to have your credentials to the Windows Azure Web Site so that it can stop + start the website.
In more detail, the variables are:
-
* RedGateAzureFtpServer
* RedGateAzureFtpUserName
* RedGateAzureFtpPassword
-
* Install "Windows Azure PowerShell" from
* Add git to %PATH%
* Get-AzurePublishSettingsFile
* Import-AzurePublishSettingsFile <filename>
Then you'll need this in a Deploy.ps1 file in your package:
#Inputs: #$RedGateAzureFtpServer = waws-prod-db3-003.ftp.azurewebsites.windows.net #$RedGateAzureFtpUserName = User01 #$RedGateAzureFtpPassword = ******** # Uploads the contents of the deployed package to the given ftp site, then delete the old files # This is done by uploading to a temporary file # checking the upload worked # and then swap the directories to `deploy` the website # the finally delete the old wwwroot $errors = "" if ($null -eq $RedGateAzureFtpServer) { $errors = $errors + ", RedGateAzureFtpServer" } if ($null -eq $RedGateAzureFtpUserName) { $errors = $errors + ", RedGateAzureFtpUserName" } if ($null -eq $RedGateAzureFtpPassword) { $errors = $errors + ", RedGateAzureFtpPassword" } if (0 -ne $errors.length) { # Throw an error and stop deployment Throw ($errors.trim(", ") + " must be set to push to ftp site") } $webrootDir = "site/wwwroot" $guid1 = [guid]::NewGuid() $guid2 = [guid]::NewGuid() $ftpUrl = "ftp://$RedGateAzureFtpServer/$webrootDir" $ftpTemp1 = "ftp://$RedGateAzureFtpServer/$guid1" $azureWebsite = $RedGateAzureFtpUserName.split('\')[0] $ftpTemp2 = "ftp://$RedGateAzureFtpServer/$guid2" $oldWebrootDir = "/$guid2" # Upload the files Function FtpUpload ([string]$webroot, [string]$localdirectory) { cd $localdirectory $files = Get-ChildItem -recurse FTPCreateFolder (New-Object System.Uri($webroot)) foreach($file in $files) { #Ignore the nuget package used for deployment if ($file.Name -eq "$RedGatePackageNameAndVersion.nupkg") { continue } $uri = New-Object System.Uri($webroot + $file.FullName.Replace($localdirectory,"")) # if a folder if( $file.DirectoryName -eq $null) { Write-Host "Create folder, URI: $uri" FtpCreateFolder $uri } else { Write-Host "Upload file, URI: $uri, File: " + $file.FullName FtpUploadFile $uri $file.FullName } } } Function FtpUploadFile ([System.Uri]$uri, [string]$filePath) { $ftp = [System.Net.FtpWebRequest]::Create($uri) $ftp.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile $ftp.Credentials = new-object System.Net.NetworkCredential($RedGateAzureFtpUserName,$RedGateAzureFtpPassword) $ftp.UseBinary = $true $ftp.UsePassive = $true $content = [System.IO.File]::ReadAllBytes($filePath) $ftp.ContentLength = $content.Length $rs = $ftp.GetRequestStream() $rs.Write($content, 0, $content.Length) $rs.Close() $rs.Dispose() } Function FtpCreateFolder ([System.Uri]$uri) { $ftp = [System.Net.FtpWebRequest]::Create($uri) $ftp.Method = [System.Net.WebRequestMethods+Ftp]::MakeDirectory $ftp.Credentials = new-object System.Net.NetworkCredential($RedGateAzureFtpUserName,$RedGateAzureFtpPassword) try { $rs = $ftp.GetResponse() } catch [System.Exception] { } if( $rs -ne $null ) { $rs.Close() } } # Reads the entire stream in one go and return it # instead of reading stream line by line Function Receive-Stream ([System.IO.Stream]$reader) { $encoding = [System.Text.Encoding]::GetEncoding( $null ) $output = "" [byte[]]$buffer = new-object byte[] 4096 [int]$total = [int]$count = 0 do { $count = $reader.Read($buffer, 0, $buffer.Length) $output += $encoding.GetString($buffer, 0, $count) } while ($count -gt 0) $reader.Close() $output } # Delete the directory $path # Start by recursively deleting files inside # then remove the directory itself Function FtpDelete ([string]$path) { $itemsOnFTPtoDelete = New-Object System.Collections.ArrayList $uri = New-Object System.Uri($path) $ftp = [System.Net.FtpWebRequest]::Create($uri) $ftp.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails $ftp.Credentials = new-object System.Net.NetworkCredential($RedGateAzureFtpUserName,$RedGateAzureFtpPassword) try { $rs = $ftp.GetResponse() $cache = (Receive-Stream $rs.GetResponseStream()) # Split up the cache into a useable format with an item on each line $list = $cache -replace "(?:.|\n)*<PRE>\s+((?:.*|\n)+)\s+</PRE>(?:.|\n)*",'$1' -split "`n" # Convert the list of items into a useable format foreach($line in $list) { $null, $null, [string]$length, $name = $line -split '\s+' $name = ($name -join " ") if ($name.Length -eq 0) { continue } $ftpItem = New-Object PSObject -Property @{ FullName = $path.trim().trim('/') + '/' + $name Type = $(if($length -eq (($length -as [int]) -as [string])) { "File" } else { $length }) } [void]$itemsOnFTPtoDelete.Add($ftpItem) } $rs.Close() # Delete each file, recursively deleting directories foreach ($item in $itemsOnFTPtoDelete) { $uri = New-Object System.Uri($item.FullName) if ("<DIR>" -ne $item.Type) { FtpDeleteFile $uri } else { FtpDelete $item.FullName } } FtpDeleteEmptyDirectory (New-Object System.Uri($path)) } catch { } } Function FtpDeleteFile ([System.Uri]$uri) { Write-Host "Deleting $uri" $ftp = [System.Net.FtpWebRequest]::Create($uri) $ftp.Method = [System.Net.WebRequestMethods+Ftp]::DeleteFile $ftp.Credentials = new-object System.Net.NetworkCredential($RedGateAzureFtpUserName,$frpPassword) try { $rs = $ftp.GetResponse() } catch [System.Exception] { } if( $rs -ne $null ) { $rs.Close() } } Function FtpDeleteEmptyDirectory ([System.Uri]$uri) { Write-Host "Deleting directory $uri" $ftp = [System.Net.FtpWebRequest]::Create($uri) $ftp = [System.Net.FtpWebRequest]$ftp $ftp.Method = [System.Net.WebRequestMethods+Ftp]::RemoveDirectory $ftp.Credentials = new-object System.Net.NetworkCredential($RedGateAzureFtpUserName,$RedGateAzureFtpPassword) try { $rs = $ftp.GetResponse() } catch [System.Exception] { } if( $rs -ne $null ) { $rs.Close() } } Function FtpRename ([System.Uri]$uri, [string]$newname) { Write-Host "Renaming $uri to $newname" $ftp = [System.Net.FtpWebRequest]::Create($uri) $ftp.Method = [System.Net.WebRequestMethods+Ftp]::Rename $ftp.Credentials = new-object System.Net.NetworkCredential($RedGateAzureFtpUserName,$RedGateAzureFtpPassword) $ftp.RenameTo = $newname try { $rs = $ftp.GetResponse() } catch [System.Exception] { } if( $rs -ne $null ) { $rs.Close() } } # Checks the files in $webroot versus $localdirectory # recursively called for directories Function FtpValidate ([string]$webroot, [string]$localdirectory) { Write-Host "Validating directory $localdirectory was uploaded" $itemsOnFTP = New-Object System.Collections.ArrayList cd $localdirectory $uploadedFiles = Get-ChildItem $uri = New-Object System.Uri($webroot) $ftp = [System.Net.FtpWebRequest]::Create($uri) $ftp.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails $ftp.Credentials = new-object System.Net.NetworkCredential($RedGateAzureFtpUserName,$RedGateAzureFtpPassword) try { # Get the items stored on the ftp at the webroot location $rs = $ftp.GetResponse() $cache = (Receive-Stream $rs.GetResponseStream()) $list = $cache -replace "(?:.|\n)*<PRE>\s+((?:.*|\n)+)\s+</PRE>(?:.|\n)*",'$1' -split "`n" foreach($line in $list) { $null, $null, [string]$length, $name = $line -split '\s+' $name = ($name -join " ").Trim() if ($name.Length -eq 0) { continue } $ftpItem = New-Object PSObject -Property @{ Name = $name FullName = $webroot.trim().trim('/') + '/' + $name Length = $(if($length -eq (($length -as [int]) -as [string])) { [int]$length } else { $null }) Type = $(if($length -eq (($length -as [int]) -as [string])) { "File" } else { $length }) } [void]$itemsOnFTP.Add($ftpItem) } $rs.Close() } catch {} foreach ($file in $uploadedFiles) { # ignore the package used for deployment if ($file.Name -eq "$RedGatePackageNameAndVersion.nupkg") { continue } # Check each item has been uploaded correctly Write-Host "Validating item: $file" $found = $null foreach ($ftpItem in $itemsOnFTP) { if ($ftpItem.Name -eq $file.Name) { $found = $ftpItem } } # If it doesn't exist on ftp then error if ($found -eq $null) { throw "$file failed to uploaded" } # if a folder if( $file.DirectoryName -eq $null) { # check the internals are the same FtpValidate $found.FullName $file.FullName } else { # check the file lengths are equal if ($found.Length -ne $file.Length) { throw "$file was not uploaded correctly" } } } } $myDir = Split-Path -Parent $MyInvocation.MyCommand.Path Write-Host "Uploading new files" FtpUpload $ftpTemp1 $myDir Write-Host "Validating upload" FtpValidate $ftpTemp1 $myDir Write-Host "Validation Successful" Write-Host "Swapping to new website" Stop-AzureWebsite $azureWebsite FtpRename (New-Object System.Uri($ftpUrl)) $oldWebrootDir FtpRename (New-Object System.Uri($ftpTemp1)) $webrootDir Start-AzureWebsite $azureWebsite Write-Host "Delete old files" FtpDelete $ftpTemp2