5
votes

I'm attempting to set up integration testing for an Azure Function app. Deployment is going fine, but I need a way to programatically get the default key to run my integration tests.

I've tried what is linked here - Get Function & Host Keys of Azure Function In Powershell - but cannot get the listsecrets working in my ARM deployment template. Listsecrets is not recognized.

Does anyone know how to get this key with an ARM template and/or powershell?

2

2 Answers

1
votes

After updates to Microsoft's ARM APIs it is now possible to retrieve Azure Function keys directly from the ARM deployment outputs.

Example

{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "appServiceName": {
    "type": "string"
    }
  },
  "variables": {
    "appServiceId": "[resourceId('Microsoft.Web/sites', parameters('appServiceName'))]"
  },
//... implementation omitted
  "outputs": {
    "functionKeys": {
      "type": "object",
      "value": "[listkeys(concat(variables('appServiceId'), '/host/default'), '2018-11-01')]"
    }
  }
}

Outputs

The Outputs property will contain a Newtonsoft.Json.Linq.JObject entry that contains all of the keys for the Azure Function i.e., master, system keys, and function keys (which includes the default key). Unfortunately, the JObject combined with the deployment variable type is a bit tortuous to get into and you should be warned, is case sensitive. (If you're working in PowerShell it can be massaged into hashtables for consumption. See Bonus below.)

$results = New-AzResourceGroupDeployment...
$keys = results.Outputs.functionKeys.Value.functionKeys.default.Value

Bonus

The code below gets rid of the extra .Value calls.

function Convert-OutputsToHashtable {
  param (
    [ValidateNotNull()]
    [object]$Outputs
  )

  $Outputs.GetEnumerator() | ForEach-Object { $ht = @{} } {
    if ($_.Value.Value -is [Newtonsoft.Json.Linq.JObject]) {
      $ht[$_.Key] = ConvertFrom-Json $_.Value.Value.ToString() -AsHashtable
    } else {
      $ht[$_.Key] = $_.Value.Value
    }
  } { $ht }

}
3
votes

I ended up being able to run an Azure Powershell script in a VSTS task and output the variable to a build key. I am attaching the script so others can use.

#Requires -Version 3.0

Param(
    [string] [Parameter(Mandatory=$true)] $ResourceGroup,
    [string] [Parameter(Mandatory=$true)] $FunctionAppName
)

$content = Get-AzureRmWebAppPublishingProfile -ResourceGroupName $ResourceGroup -Name $FunctionAppName -OutputFile creds.xml -Format WebDeploy
$username = Select-Xml -Content $content -XPath "//publishProfile[@publishMethod='MSDeploy']/@userName"
$password = Select-Xml -Content $content -XPath "//publishProfile[@publishMethod='MSDeploy']/@userPWD"
$accessToken = "Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password)))

$masterApiUrl = "https://$FunctionAppName.scm.azurewebsites.net/api/functions/admin/masterkey"
$masterKeyResult = Invoke-RestMethod -Uri $masterApiUrl -Headers @{"Authorization"=$accessToken;"If-Match"="*"}
$masterKey = $masterKeyResult.Masterkey

$functionApiUrl = "https://$FunctionAppName.azurewebsites.net/admin/host/keys?code=$masterKey"
$functionApiResult = Invoke-WebRequest -UseBasicParsing -Uri $functionApiUrl
$keysCode = $functionApiResult.Content | ConvertFrom-Json
$functionKey = $keysCode.Keys[0].Value

$saveString = "##vso[task.setvariable variable=FunctionAppKey;]{0}" -f $functionKey

Write-Host ("Writing: {0}" -f $saveString)
Write-Output ("{0}" -f $saveString)