Application Insights - Annotate Release

Octopus.Script exported 2020-04-11 by harrisonmeister belongs to ‘Azure’ category.

Marks a release point in Application Insights.

Parameters

When steps based on the template are included in a project’s deployment process, the parameters below can be set.

Application Id

ApplicationId

The Application Insights Application Id.

Api Key

ApiKey

The API Key to use to configure the Application Insights application.

Release Name

ReleaseName = #{Octopus.Release.Number}

The release name. Typically bound to #{Octopus.Release.Number}

Release Properties

ReleaseProperties

List of key/value pairs separated by a new-line. For example:

ReleaseDescription = Release with annotation
TriggerBy = John Doe

Script body

Steps based on this template will execute the following PowerShell script.

$securityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12
[Net.ServicePointManager]::SecurityProtocol = $securityProtocol

$applicationId = $OctopusParameters["ApplicationId"]
$apiKey = $OctopusParameters["ApiKey"]
$releaseName = $OctopusParameters["ReleaseName"]
$properties = $OctopusParameters["ReleaseProperties"]

$releaseProperties = $null

if ($properties -ne $null)
{
    $releaseProperties = ConvertFrom-StringData -StringData $properties
}

# background info on how fwlink works: After you submit a web request, many sites redirect through a series of intermediate pages before you finally land on the destination page.
# So when calling Invoke-WebRequest, the result it returns comes from the final page in any redirect sequence. Hence, I set MaximumRedirection to 0, as this prevents the call to 
# be redirected. By doing this, we get a resposne with status code 302, which indicates that there is a redirection link from the response body. We grab this redirection link and 
# construct the url to make a release annotation.
# Here's how this logic is going to works
# 1. Client send http request, such as:  http://go.microsoft.com/fwlink/?LinkId=625115
# 2. FWLink get the request and find out the destination URL for it, such as:  http://www.bing.com
# 3. FWLink generate a new http response with status code "302" and with destination URL "http://www.bing.com". Send it back to Client.
# 4. Client, such as a powershell script, knows that status code "302" means redirection to new a location, and the target location is "http://www.bing.com"
function GetRequestUrlFromFwLink($fwLink)
{
    $request = Invoke-WebRequest -Uri $fwLink -MaximumRedirection 0 -UseBasicParsing -ErrorAction Ignore
    if ($request.StatusCode -eq "302") {
        return $request.Headers.Location
    }
    
    return $null
}

function CreateAnnotation($grpEnv)
{
	$retries = 1
	$success = $false
	while (!$success -and $retries -lt 6) {
	    $location = "$grpEnv/applications/$applicationId/Annotations?api-version=2015-11"
		    
		Write-Host "Invoke a web request for $location to create a new release annotation. Attempting $retries"
		set-variable -Name createResultStatus -Force -Scope Local -Value $null
		set-variable -Name createResultStatusDescription -Force -Scope Local -Value $null
		set-variable -Name result -Force -Scope Local

		try {
			$result = Invoke-WebRequest -Uri $location -Method Put -Body $bodyJson -Headers $headers -ContentType "application/json; charset=utf-8" -UseBasicParsing
		} catch {
		    if ($_.Exception){
		        if($_.Exception.Response) {
    				$createResultStatus = $_.Exception.Response.StatusCode.value__
    				$createResultStatusDescription = $_.Exception.Response.StatusDescription
    			}
    			else {
    				$createResultStatus = "Exception"
    				$createResultStatusDescription = $_.Exception.Message
    			}
		    }
		}

		if ($result -eq $null) {
			if ($createResultStatus -eq $null) {
				$createResultStatus = "Unknown"
			}
			if ($createResultStatusDescription -eq $null) {
				$createResultStatusDescription = "Unknown"
			}
		}
 		else {
			    $success = $true			         
        }

		if ($createResultStatus -eq 409 -or $createResultStatus -eq 404 -or $createResultStatus -eq 401) # no retry when conflict or unauthorized or not found
		{
			break
		}

		$retries = $retries + 1
		sleep 1
	}

	$createResultStatus
	$createResultStatusDescription
	return
}

# Need powershell version 3 or greater for script to run
$minimumPowershellMajorVersion = 3
if ($PSVersionTable.PSVersion.Major -le $minimumPowershellMajorVersion) {
   Write-Host "Need powershell version $minimumPowershellMajorVersion or greater to create release annotation"
   return
}

$currentTime = (Get-Date).ToUniversalTime()
$annotationDate = $currentTime.ToString("MMddyyyy_HHmmss")
set-variable -Name requestBody -Force -Scope Script
$requestBody = @{}
$requestBody.Id = [GUID]::NewGuid()
$requestBody.AnnotationName = $releaseName
$requestBody.EventTime = $currentTime.GetDateTimeFormats("s")[0] # GetDateTimeFormats returns an array
$requestBody.Category = "Deployment"

if ($releaseProperties -eq $null) {
    $properties = @{}
} else {
    $properties = $releaseProperties    
}
$properties.Add("ReleaseName", $releaseName)

$requestBody.Properties = ConvertTo-Json($properties) -Compress

$bodyJson = [System.Text.Encoding]::UTF8.GetBytes(($requestBody | ConvertTo-Json))
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("X-AIAPIKEY", $apiKey)

set-variable -Name createAnnotationResult1 -Force -Scope Local -Value $null
set-variable -Name createAnnotationResultDescription -Force -Scope Local -Value ""

# get redirect link from fwlink
$requestUrl = GetRequestUrlFromFwLink("http://go.microsoft.com/fwlink/?prd=11901&pver=1.0&sbp=Application%20Insights&plcid=0x409&clcid=0x409&ar=Annotations&sar=Create%20Annotation")
if ($requestUrl -eq $null) {
    $output = "Failed to find the redirect link to create a release annotation"
    throw $output
}

$createAnnotationResult1, $createAnnotationResultDescription = CreateAnnotation($requestUrl)
if ($createAnnotationResult1) 
{
     $output = "Failed to create an annotation with Id: {0}. Error {1}, Description: {2}." -f $requestBody.Id, $createAnnotationResult1, $createAnnotationResultDescription
	 throw $output
}

$str = "Release annotation created. Id: {0}." -f $requestBody.Id
Write-Host $str

Provided under the Apache License version 2.0.

Report an issue

To use this template in Octopus Deploy, copy the JSON below and paste it into the Library → Step templates → Import dialog.

{
  "Id": "c3278ce2-9cdb-46fd-96ce-e1d03ac327fe",
  "Name": "Application Insights - Annotate Release",
  "Description": "Marks a release point in Application Insights.",
  "Version": 8,
  "ExportedAt": "2020-04-11T15:22:12.542Z",
  "ActionType": "Octopus.Script",
  "Author": "harrisonmeister",
  "Packages": [],
  "Parameters": [
    {
      "Id": "4e276bad-2a13-4dc2-bd54-5708a76cf662",
      "Name": "ApplicationId",
      "Label": "Application Id",
      "HelpText": "The Application Insights Application Id.",
      "DefaultValue": null,
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "f818317b-6b62-4695-9272-7062a4c1c601",
      "Name": "ApiKey",
      "Label": "Api Key",
      "HelpText": "The API Key to use to configure the Application Insights application.",
      "DefaultValue": null,
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "a241d2b7-99e0-4ed5-9ed1-5b003d855b33",
      "Name": "ReleaseName",
      "Label": "Release Name",
      "HelpText": "The release name. Typically bound to #{Octopus.Release.Number}",
      "DefaultValue": "#{Octopus.Release.Number}",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "bdd7161a-682c-4c6b-98dd-bee990326ed0",
      "Name": "ReleaseProperties",
      "Label": "Release Properties",
      "HelpText": "List of key/value pairs separated by a new-line. For example:\n\n```\nReleaseDescription = Release with annotation\nTriggerBy = John Doe\n```",
      "DefaultValue": null,
      "DisplaySettings": {
        "Octopus.ControlType": "MultiLineText"
      }
    }
  ],
  "Properties": {
    "Octopus.Action.Script.Syntax": "PowerShell",
    "Octopus.Action.Script.ScriptBody": "$securityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12\n[Net.ServicePointManager]::SecurityProtocol = $securityProtocol\n\n$applicationId = $OctopusParameters[\"ApplicationId\"]\n$apiKey = $OctopusParameters[\"ApiKey\"]\n$releaseName = $OctopusParameters[\"ReleaseName\"]\n$properties = $OctopusParameters[\"ReleaseProperties\"]\n\n$releaseProperties = $null\n\nif ($properties -ne $null)\n{\n    $releaseProperties = ConvertFrom-StringData -StringData $properties\n}\n\n# background info on how fwlink works: After you submit a web request, many sites redirect through a series of intermediate pages before you finally land on the destination page.\n# So when calling Invoke-WebRequest, the result it returns comes from the final page in any redirect sequence. Hence, I set MaximumRedirection to 0, as this prevents the call to \n# be redirected. By doing this, we get a resposne with status code 302, which indicates that there is a redirection link from the response body. We grab this redirection link and \n# construct the url to make a release annotation.\n# Here's how this logic is going to works\n# 1. Client send http request, such as:  http://go.microsoft.com/fwlink/?LinkId=625115\n# 2. FWLink get the request and find out the destination URL for it, such as:  http://www.bing.com\n# 3. FWLink generate a new http response with status code \"302\" and with destination URL \"http://www.bing.com\". Send it back to Client.\n# 4. Client, such as a powershell script, knows that status code \"302\" means redirection to new a location, and the target location is \"http://www.bing.com\"\nfunction GetRequestUrlFromFwLink($fwLink)\n{\n    $request = Invoke-WebRequest -Uri $fwLink -MaximumRedirection 0 -UseBasicParsing -ErrorAction Ignore\n    if ($request.StatusCode -eq \"302\") {\n        return $request.Headers.Location\n    }\n    \n    return $null\n}\n\nfunction CreateAnnotation($grpEnv)\n{\n\t$retries = 1\n\t$success = $false\n\twhile (!$success -and $retries -lt 6) {\n\t    $location = \"$grpEnv/applications/$applicationId/Annotations?api-version=2015-11\"\n\t\t    \n\t\tWrite-Host \"Invoke a web request for $location to create a new release annotation. Attempting $retries\"\n\t\tset-variable -Name createResultStatus -Force -Scope Local -Value $null\n\t\tset-variable -Name createResultStatusDescription -Force -Scope Local -Value $null\n\t\tset-variable -Name result -Force -Scope Local\n\n\t\ttry {\n\t\t\t$result = Invoke-WebRequest -Uri $location -Method Put -Body $bodyJson -Headers $headers -ContentType \"application/json; charset=utf-8\" -UseBasicParsing\n\t\t} catch {\n\t\t    if ($_.Exception){\n\t\t        if($_.Exception.Response) {\n    \t\t\t\t$createResultStatus = $_.Exception.Response.StatusCode.value__\n    \t\t\t\t$createResultStatusDescription = $_.Exception.Response.StatusDescription\n    \t\t\t}\n    \t\t\telse {\n    \t\t\t\t$createResultStatus = \"Exception\"\n    \t\t\t\t$createResultStatusDescription = $_.Exception.Message\n    \t\t\t}\n\t\t    }\n\t\t}\n\n\t\tif ($result -eq $null) {\n\t\t\tif ($createResultStatus -eq $null) {\n\t\t\t\t$createResultStatus = \"Unknown\"\n\t\t\t}\n\t\t\tif ($createResultStatusDescription -eq $null) {\n\t\t\t\t$createResultStatusDescription = \"Unknown\"\n\t\t\t}\n\t\t}\n \t\telse {\n\t\t\t    $success = $true\t\t\t         \n        }\n\n\t\tif ($createResultStatus -eq 409 -or $createResultStatus -eq 404 -or $createResultStatus -eq 401) # no retry when conflict or unauthorized or not found\n\t\t{\n\t\t\tbreak\n\t\t}\n\n\t\t$retries = $retries + 1\n\t\tsleep 1\n\t}\n\n\t$createResultStatus\n\t$createResultStatusDescription\n\treturn\n}\n\n# Need powershell version 3 or greater for script to run\n$minimumPowershellMajorVersion = 3\nif ($PSVersionTable.PSVersion.Major -le $minimumPowershellMajorVersion) {\n   Write-Host \"Need powershell version $minimumPowershellMajorVersion or greater to create release annotation\"\n   return\n}\n\n$currentTime = (Get-Date).ToUniversalTime()\n$annotationDate = $currentTime.ToString(\"MMddyyyy_HHmmss\")\nset-variable -Name requestBody -Force -Scope Script\n$requestBody = @{}\n$requestBody.Id = [GUID]::NewGuid()\n$requestBody.AnnotationName = $releaseName\n$requestBody.EventTime = $currentTime.GetDateTimeFormats(\"s\")[0] # GetDateTimeFormats returns an array\n$requestBody.Category = \"Deployment\"\n\nif ($releaseProperties -eq $null) {\n    $properties = @{}\n} else {\n    $properties = $releaseProperties    \n}\n$properties.Add(\"ReleaseName\", $releaseName)\n\n$requestBody.Properties = ConvertTo-Json($properties) -Compress\n\n$bodyJson = [System.Text.Encoding]::UTF8.GetBytes(($requestBody | ConvertTo-Json))\n$headers = New-Object \"System.Collections.Generic.Dictionary[[String],[String]]\"\n$headers.Add(\"X-AIAPIKEY\", $apiKey)\n\nset-variable -Name createAnnotationResult1 -Force -Scope Local -Value $null\nset-variable -Name createAnnotationResultDescription -Force -Scope Local -Value \"\"\n\n# get redirect link from fwlink\n$requestUrl = GetRequestUrlFromFwLink(\"http://go.microsoft.com/fwlink/?prd=11901&pver=1.0&sbp=Application%20Insights&plcid=0x409&clcid=0x409&ar=Annotations&sar=Create%20Annotation\")\nif ($requestUrl -eq $null) {\n    $output = \"Failed to find the redirect link to create a release annotation\"\n    throw $output\n}\n\n$createAnnotationResult1, $createAnnotationResultDescription = CreateAnnotation($requestUrl)\nif ($createAnnotationResult1) \n{\n     $output = \"Failed to create an annotation with Id: {0}. Error {1}, Description: {2}.\" -f $requestBody.Id, $createAnnotationResult1, $createAnnotationResultDescription\n\t throw $output\n}\n\n$str = \"Release annotation created. Id: {0}.\" -f $requestBody.Id\nWrite-Host $str",
    "Octopus.Action.Script.ScriptSource": "Inline"
  },
  "Category": "Azure",
  "HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/75443764cd38076d/step-templates/application-insights-annotate-release.json",
  "Website": "/step-templates/c3278ce2-9cdb-46fd-96ce-e1d03ac327fe",
  "Logo": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADNQTFRF////AHjXf7vrv931QJrh7/f8EIDaIIncMJHfYKvmz+b3n8zw3+76j8Ttr9XycLPpUKLkkKvYFAAABGZJREFUeNrsnNmCqjoQRc1MEiD8/9cer7Yt2KBJZQC8ez07sKlKTQlcLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoUSnt8YxXlFuGHSbIaxvj+fip4btkLn1blkWLaF5v03yLhLOYlVuGYfMOMZzNGxCOzhjTJqFkXnjq3Dr1yyvPI3hGl3Ih3zzHHNKudRstRhX5O58vIcShY67Gq6EPIESlzUWvazaGAOGbvU7ArDu/g8M4o8opDZWvbvPzlL/MMBE8jT9T9W7PbAJlHPTBFRf9yVTEcs63msXz2UHLSgf650G/d5t+wjbxxB2UCMqGrk8/LFSD7uJMeNt5bcJCyQZyAe5Fo9KYfWS2flQrr4b4tpuzaeWjYs49rt9LHf9uZD7+VbyVi9EBNrjYjuq2sxQOrl+p+HuBVu45qvqfq691ttYFQ5KyKbyJgaIY/NGxrlWZwlwGvmvu1oY3PuAv0niTq6tZ78jk//9uc1r1r4lQki7y7sp2Tu4V1y2iLoqFTqi1lIGcpFiebrZNZ1dOkF0cCIlO8jQ47nCkam9Lilz9GhDF1I6XGLzfnhwDIIZVfI7+8SSgfHsijqXENOGJF5QorG4EcW0OrScqX/dDrXpr70Ut/BII+1OfECPuYz/NWxYmgrCsUskxPvyhgmrw+WGZ6lGTuOlIyCYWTFyWjpM5KIZRUIOwjRNYRQ6tZF9BXtk8hWAHPtLNJ727Fq0JSkC1FDRRF0Jalj0d5qVh2KEpM2TuSsCYTCT6ZkdmFYI9LrYp5QayWbo6NXlZwcRD/61pth5Fq5EX423QQxNjhqWvvklkljOLkYjrmphXPZOJOk6Pg7HKMsrtQKcowzZoK3rx1ZUelGMdQA/HaKkjAt2RgqpZeYqbNbH7Hp2ct4nqfSPOfe0ftiSTZJydOV6rG5bQbyLK+nRuCC0343PzDgiOXyQA5c14BTZi98uR/5KJ1SnatLdoO50WWBQZPTq0VgsklU3h932actuo17ayrHrb/3ykiegd3KbqF2wbV6RrlsJ07yLcpsWFTul9RyK6ZScr+tk7oNrFj0o7HQUlj4EiEvJ6rPLKSmlMZCrksl1OnLaRkxc+/HB1naMhNtT/6yM2bDs6azCRHrM3aVPN7aW8irD/10B8njpAMcsl8okXcdKrl4sPsLmQVy/Sj90ucPRc/d/Bxxj+dXSpCayen32D+hLi16MsIV8gfCXrYp6ySsiJKRUF0XXiLpVbFU+fNv4r7mOwhFsX4ZdwpSi1DYs2jb6ebZ9788cblTzMrYhu7sf/17IFdtuviJ2ioHA6pMHkoH4CLUeMBU7iGkxuM/YgcdderF9ibRdc7O982F1HpYhjfWUe+x5a6pjop9iNLfoePvlsdZdTSMwfxSmTY20Q0eHnUNzga1edeNmmqbg18aMVR1L9vwSXHF9TfIWBxpKLs2hj3eQeBC0USvp2HHF3eIkRdhFOd6ER8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/I/4J8AAo/80BciBec4AAAAASUVORK5CYII=",
  "$Meta": {
    "Type": "ActionTemplate"
  }
}

History

Page updated on Saturday, April 11, 2020