Yesterday Sandro Pereira dropped me a line with a question…
“Hey Mike how do I monitor API Connections, one of mine broke again”
This is something ive thought about a while back and never got around to blogging about so this is for Sandro.
A while ago I created a Pester test in Powershell which I just ran by hand which lets me check if any of the connectors are not connected and fail a test. I hadnt got around to doing much about this in a more automated fashion so I had been just running this by hand occasionally. The powershell is below if anyone wants it.
The question is however how can we take this a step further and monitor those connections.
$apiConnections = Get-AzResource -ResourceGroupName $resourcegroup -ResourceType Microsoft.Web/connections
Describe 'API Connections'{
foreach($apiConnection in $apiConnections){
#Get the connector json
$connectorUrl = $apiConnection.ResourceId + '?api-version=2018-07-01-preview'
$connectorJson = az rest --method get --uri $connectorUrl
$connectorJsonText = $connectorJson | ConvertFrom-Json
It "$($apiConnection.Name) overall status test" {
#Write-Host ($connectorJson | Format-List | Out-String)
$properties = $connectorJsonText.properties
$overallStatus = $properties.overallStatus
#Write-Host $apiConnection.Name ' is ' $overallStatus
$overallStatus | Should Be 'Connected'
}
}
}
Well if we think back to the Pester for a moment all it was really doing was calling the Azure API and checking the response.
We can use this to check this in an automated fashion. The way I am going to plug this into my monitoring in this example is based on the diagram below.
I am going to use my API Management which has a managed identity setup and I gave it reader RBAC access to my resource group. I will then create an API operation which will let me provide the subscription id, the resource group name and the connector name. I will then call the API and it will format a url and forward the call to the Azure Management API using the managed identity for APIM for authentication. In the response my APIM policy will check the json returned to see that the connector status is connected which indicates success or something else which indicates an error.
I will then be able to call the API like below
GET https://[mikes-apim].azure-api.net/azure/monitoring/api-connection/{subscriptionid}/{resourcegroupname}/{connectorname}/is-connected
I can then setup a web test in app insights using the url ping test and supply a subscription key for my APIM as a url query parameter to allow App Insights to ping my APIM to check the connector is connected. Using the App Insights web test I can then setup action groups to determine what to do if the test fails, eg raise an alert or take a corrective action.
With my web availability test in APIM I can then see the graph showing the connector is working ok and when it is not connected.
What if I dont want to use APIM
Im sure you could implement the similar approaches with a Logic App or a Function to query the management api and check the property and return a true or false to plug into your monitoring solution. The key thing for me was already having the managed identity for APIM made it easy to use APIM but you could setup the same for a Logic App or Function and give them the Reader RBAC role
The Policy for APIM
If anyone wants to see the policy I used to configure APIM to do this its below.
<policies>
<inbound>
<base />
<set-variable name="resourceUrl" value="@{
var url = "";
url += "/subscriptions/";
url += context.Request.MatchedParameters["subscriptionid"];
url += "/resourceGroups/";
url += context.Request.MatchedParameters["resourcegroup"];
url += "/providers/Microsoft.Web/connections/";
url += context.Request.MatchedParameters["resourcename"];
return url;
}" />
<rewrite-uri template="@((string)context.Variables["resourceUrl"])" copy-unmatched-params="false" />
<set-query-parameter name="api-version" exists-action="override">
<value>2018-07-01-preview</value>
</set-query-parameter>
<authentication-managed-identity resource="https://management.azure.com" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<set-variable name="responseBody" value="@(context.Response.Body.As<string>(preserveContent: true))" />
<set-variable name="isConnected" value="@{
JObject azureResponse = JObject.Parse((string)context.Variables["responseBody"]);
var connectedStatus = azureResponse["properties"]["overallStatus"];
if(connectedStatus.ToString().ToUpper() == "CONNECTED")
{
return true;
}
else
{
return false;
}
}" />
<choose>
<when condition="@(((bool)context.Variables["isConnected"]) == true)">
<return-response>
<set-status code="200" reason="Ok" />
<set-body>The API Connection is connected</set-body>
</return-response>
</when>
<otherwise>
<return-response>
<set-status code="500" reason="Error" />
<set-body>The API Connection is NOT connected</set-body>
</return-response>
</otherwise>
</choose>
</outbound>
<on-error>
<base />
</on-error>
</policies>
Hopefully this is a nice simple way to setup some monitoring for those API connections with the tools we have available today.