Application Insights - Annotate Release with Azure CLI and RBAC

Octopus.Script exported 2024-05-17 by NielsDM belongs to ‘Azure’ category.

Marks a release point in Application Insights. This step template uses Azure CLI and Role-Based Access Control instead of an API Key. Used application-insights-annotate-release.json as inspiration.

Parameters

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

Application Insights Account

AppInsights.ApplicationInsightsAccount =

Azure account for the Application Insights instance

Application Name

AppInsights.ApplicationName =

The Application Insights Application name.

Resource Group

AppInsights.ResourceGroup =

The Resource Group of the Application Insights instance

Release Name

AppInsights.ReleaseName = #{Octopus.Release.Number}

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

Release Properties

AppInsights.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.

# Function to decrypt data
function Convert-PasswordToPlainText {
	$base64password = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($OctopusParameters["AppInsights.ApplicationInsightsAccount.Password"]))
    return [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64password))
}

# Function to ensure all Unicode characters in a JSON string are properly escaped
function Convert-UnicodeToEscapeHex {
  param (
    [parameter(Mandatory = $true)][string]$JsonString
  )
  $JsonObject = ConvertFrom-Json -InputObject $JsonString
  foreach ($property in $JsonObject.PSObject.Properties) {
    $name = $property.Name
    $value = $property.Value
    if ($value -is [string]) {
      $value = [regex]::Unescape($value)
      $OutputString = ""
      foreach ($char in $value.ToCharArray()) {
        $dec = [int]$char
        if ($dec -gt 127) {
          $hex = [convert]::ToString($dec, 16)
          $hex = $hex.PadLeft(4, '0')
          $OutputString += "\u$hex"
        }
        else {
          $OutputString += $char
        }
      }
      $JsonObject.$name = $OutputString
    }
  }
  return ConvertTo-Json -InputObject $JsonObject -Compress
}

$applicationName = $OctopusParameters["AppInsights.ApplicationName"]
$resourceGroup = $OctopusParameters["AppInsights.ResourceGroup"]
$releaseName = $OctopusParameters["AppInsights.ReleaseName"]
$properties = $OctopusParameters["AppInsights.ReleaseProperties"]

# Authenticate via Service Principal
$securePassword = Convert-PasswordToPlainText
$azEnv = if($OctopusParameters["AppInsights.ApplicationInsightsAccount.AzureEnvironment"]) { $OctopusParameters["AppInsights.ApplicationInsightsAccount.AzureEnvironment"] } else { "AzureCloud" }

$azEnv = Get-AzEnvironment -Name $azEnv
if (!$azEnv) {
	Write-Error "No Azure environment could be matched given the name $($OctopusParameters["AppInsights.ApplicationInsightsAccount.AzureEnvironment"])"
	exit -2
}

Write-Verbose "Authenticating with Service Principal"

# Force any output generated to be verbose in Octopus logs.
az login --service-principal -u $OctopusParameters["AppInsights.ApplicationInsightsAccount.Client"] -p $securePassword --tenant $OctopusParameters["AppInsights.ApplicationInsightsAccount.TenantId"]

Write-Verbose "Initiating the body of the annotation"

$releaseProperties = $null

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

$annotation = @{
    Id = [GUID]::NewGuid();
    AnnotationName = $releaseName;
    EventTime = (Get-Date).ToUniversalTime().GetDateTimeFormats("s")[0];
    Category = "Deployment"; #Application Insights only displays annotations from the "Deployment" Category
    Properties = ConvertTo-Json $releaseProperties -Compress
}

$annotation = ConvertTo-Json $annotation -Compress
$annotation = Convert-UnicodeToEscapeHex -JsonString $annotation  

$body = $annotation -replace '(\\+)"', '$1$1"' -replace "`"", "`"`""

Write-Verbose "Send the annotation to Application Insights"

az rest --method put --uri "/subscriptions/$($OctopusParameters["AppInsights.ApplicationInsightsAccount.SubscriptionNumber"])/resourceGroups/$($resourceGroup)/providers/microsoft.insights/components/$($applicationName)/Annotations?api-version=2015-05-01" --body "$($body) "

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": "bc4eae30-786a-4974-a003-948b7a4ed023",
  "Name": "Application Insights - Annotate Release with Azure CLI and RBAC",
  "Description": "Marks a release point in Application Insights. This step template uses Azure CLI and Role-Based Access Control instead of an API Key. Used application-insights-annotate-release.json as inspiration.",
  "Version": 1,
  "ExportedAt": "2024-05-17T06:54:43.852Z",
  "ActionType": "Octopus.Script",
  "Author": "NielsDM",
  "Packages": [],
  "Parameters": [
    {
      "Id": "ef9d044d-3765-4cb0-af55-22c15ce4013c",
      "Name": "AppInsights.ApplicationInsightsAccount",
      "Label": "Application Insights Account",
      "HelpText": "Azure account for the Application Insights instance",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "AzureAccount"
      }
    },
    {
      "Id": "98174616-d9dd-4e8e-9b01-2961a061360f",
      "Name": "AppInsights.ApplicationName",
      "Label": "Application Name",
      "HelpText": "The Application Insights Application name.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "41835ca3-76d3-47f8-b863-d26c782c4ba4",
      "Name": "AppInsights.ResourceGroup",
      "Label": "Resource Group",
      "HelpText": "The Resource Group of the Application Insights instance",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "e008808c-622d-4efe-91a0-ac666d264996",
      "Name": "AppInsights.ReleaseName",
      "Label": "Release Name",
      "HelpText": "The release name. Typically bound to #{Octopus.Release.Number}",
      "DefaultValue": "#{Octopus.Release.Number}",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "551f06ad-9470-415b-aed9-dd80f3a4123d",
      "Name": "AppInsights.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": "",
      "DisplaySettings": {
        "Octopus.ControlType": "MultiLineText"
      }
    }
  ],
  "Properties": {
    "Octopus.Action.Script.Syntax": "PowerShell",
    "Octopus.Action.Script.ScriptBody": "# Function to decrypt data\nfunction Convert-PasswordToPlainText {\n\t$base64password = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($OctopusParameters[\"AppInsights.ApplicationInsightsAccount.Password\"]))\n    return [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64password))\n}\n\n# Function to ensure all Unicode characters in a JSON string are properly escaped\nfunction Convert-UnicodeToEscapeHex {\n  param (\n    [parameter(Mandatory = $true)][string]$JsonString\n  )\n  $JsonObject = ConvertFrom-Json -InputObject $JsonString\n  foreach ($property in $JsonObject.PSObject.Properties) {\n    $name = $property.Name\n    $value = $property.Value\n    if ($value -is [string]) {\n      $value = [regex]::Unescape($value)\n      $OutputString = \"\"\n      foreach ($char in $value.ToCharArray()) {\n        $dec = [int]$char\n        if ($dec -gt 127) {\n          $hex = [convert]::ToString($dec, 16)\n          $hex = $hex.PadLeft(4, '0')\n          $OutputString += \"\\u$hex\"\n        }\n        else {\n          $OutputString += $char\n        }\n      }\n      $JsonObject.$name = $OutputString\n    }\n  }\n  return ConvertTo-Json -InputObject $JsonObject -Compress\n}\n\n$applicationName = $OctopusParameters[\"AppInsights.ApplicationName\"]\n$resourceGroup = $OctopusParameters[\"AppInsights.ResourceGroup\"]\n$releaseName = $OctopusParameters[\"AppInsights.ReleaseName\"]\n$properties = $OctopusParameters[\"AppInsights.ReleaseProperties\"]\n\n# Authenticate via Service Principal\n$securePassword = Convert-PasswordToPlainText\n$azEnv = if($OctopusParameters[\"AppInsights.ApplicationInsightsAccount.AzureEnvironment\"]) { $OctopusParameters[\"AppInsights.ApplicationInsightsAccount.AzureEnvironment\"] } else { \"AzureCloud\" }\n\n$azEnv = Get-AzEnvironment -Name $azEnv\nif (!$azEnv) {\n\tWrite-Error \"No Azure environment could be matched given the name $($OctopusParameters[\"AppInsights.ApplicationInsightsAccount.AzureEnvironment\"])\"\n\texit -2\n}\n\nWrite-Verbose \"Authenticating with Service Principal\"\n\n# Force any output generated to be verbose in Octopus logs.\naz login --service-principal -u $OctopusParameters[\"AppInsights.ApplicationInsightsAccount.Client\"] -p $securePassword --tenant $OctopusParameters[\"AppInsights.ApplicationInsightsAccount.TenantId\"]\n\nWrite-Verbose \"Initiating the body of the annotation\"\n\n$releaseProperties = $null\n\nif ($properties -ne $null)\n{\n    $releaseProperties = ConvertFrom-StringData -StringData $properties\n}\n\n$annotation = @{\n    Id = [GUID]::NewGuid();\n    AnnotationName = $releaseName;\n    EventTime = (Get-Date).ToUniversalTime().GetDateTimeFormats(\"s\")[0];\n    Category = \"Deployment\"; #Application Insights only displays annotations from the \"Deployment\" Category\n    Properties = ConvertTo-Json $releaseProperties -Compress\n}\n\n$annotation = ConvertTo-Json $annotation -Compress\n$annotation = Convert-UnicodeToEscapeHex -JsonString $annotation  \n\n$body = $annotation -replace '(\\\\+)\"', '$1$1\"' -replace \"`\"\", \"`\"`\"\"\n\nWrite-Verbose \"Send the annotation to Application Insights\"\n\naz rest --method put --uri \"/subscriptions/$($OctopusParameters[\"AppInsights.ApplicationInsightsAccount.SubscriptionNumber\"])/resourceGroups/$($resourceGroup)/providers/microsoft.insights/components/$($applicationName)/Annotations?api-version=2015-05-01\" --body \"$($body) \"",
    "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-with-rbac.json",
  "Website": "/step-templates/bc4eae30-786a-4974-a003-948b7a4ed023",
  "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 Friday, May 17, 2024