Introduction
I found it rather difficult to create a classic availability test by bicep-lang, as it uses an embedded WebTest XML string that doesn't seem to be documented anywhere.
The successor of the classic URL ping test produces relief in that respect as it doesn't use the legacy WebTest format anymore. However, even there is a minor obstacle to be aware of.
Reasons for creating a web test might be obvious - you'd like to monitor the response time and availability of your HTTP endpoint from different callers spread around the globe.
However, in my specific case, I was looking for an alternative solution that mimics the Azure App Service's AlwaysOn functionality.
The thing is, the AlwaysOn feature won't let you configure a path to keep your web application warm and keeps calling the root URL. If your application doesn't provide a controller on that path, you will fill up your App Insight logs with errors 😑.
Azure provides for types of availability tests, which are:
- URL Ping Test (classic)
- Standard Test (preview)
- Multi-Step Web Test (classic)
- Custom TrackAvailability Test
This article will provide examples for the first two tests. So without further ceremony here are the templates.
Creating a URL Ping Test (Classic)
As mentioned in the introduction the classic test requires a WebTest XML string. The example below will send an HTTP GET request to www.azureblue.io and expect a status code of 200.
<WebTest
xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010"
Name="demo-classic-test"
Id="245c86e6-3488-461d-92f9-62be82435d7d"
Enabled="True"
CssProjectStructure=""
CssIteration=""
Timeout="120"
WorkItemIds=""
Description=""
CredentialUserName=""
CredentialPassword=""
PreAuthenticate="True"
Proxy="default"
StopOnError="False"
RecordedResultFile=""
ResultsLocale="">
<Items>
<Request Method="GET"
Guid="aa29472a-53b2-1b60-cd39-26c0efc17bb2"
Version="1.1"
Url="https://www.azureblue.io"
ThinkTime="0"
Timeout="120"
ParseDependentRequests="False"
FollowRedirects="True"
RecordResult="True"
Cache="False"
ResponseTimeGoal="0"
Encoding="utf-8"
ExpectedHttpStatusCode="200"
ExpectedResponseUrl=""
ReportingName=""
IgnoreHttpStatusCode="False" />
</Items>
</WebTest>
Now let's put that into place. I have carved out the relevant parameters and used string interpolation to build the XML part.
var name = 'demo-url-ping-web-test'
var rg = 'rg-article'
var subscriptionId = '<your_subscription_id>'
var appInsightsName = 'appi-demo'
var id = guid('seed')
var timeout = 120
var frequency = 300
var guidId = guid('seed')
var method = 'GET'
var url = 'https://www.azureblue.io'
var expectedHttpStatusCode = 200
var version = '1.1'
var followRedirects = 'True'
var recordResults = 'True'
var cache = 'False'
var parseDependentRequests = 'False'
var ignoreHttpStatusCode = 'False'
resource urlPingWebTest 'Microsoft.Insights/webtests@2015-05-01' = {
name: name
location: 'westeurope'
tags: {
'hidden-link:/subscriptions/${subscriptionId}/resourceGroups/${rg}/providers/microsoft.insights/components/${appInsightsName}': 'Resource'
}
kind: 'ping'
properties: {
Configuration: {
WebTest: '<WebTest xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010" Name="${name}" Id="${id}" Enabled="True" CssProjectStructure="" CssIteration="" Timeout="${timeout}" WorkItemIds="" Description="" CredentialUserName="" CredentialPassword="" PreAuthenticate="True" Proxy="default" StopOnError="False" RecordedResultFile="" ResultsLocale=""> <Items> <Request Method="${method}" Guid="${guidId}" Version="${version}" Url="${url}" ThinkTime="0" Timeout="${timeout}" ParseDependentRequests="${parseDependentRequests}" FollowRedirects="${followRedirects}" RecordResult="${recordResults}" Cache="${cache}" ResponseTimeGoal="0" Encoding="utf-8" ExpectedHttpStatusCode="${expectedHttpStatusCode}" ExpectedResponseUrl="" ReportingName="" IgnoreHttpStatusCode="${ignoreHttpStatusCode}" /> </Items> </WebTest>'
}
Description: 'Runs a classic URL ping test'
Enabled: true
Frequency: frequency
Kind: 'ping'
Locations: [
{
Id: 'emea-nl-ams-azr'
}
{
Id: 'emea-ru-msa-edge'
}
{
Id: 'apac-hk-hkn-azr'
}
{
Id: 'latam-br-gru-edge'
}
{
Id: 'emea-au-syd-edge'
}
]
Name: name
RetryEnabled: true
SyntheticMonitorId: '${name}-id'
Timeout: timeout
}
}
One way to deploy the template is with Azure CLI.
$ az deployment group create --name rollout01 --resource-group rg-article --subscription "your subscription" --template-file urlpingwebtest.bicep
Bicep supports multi-line strings since version v0.3 and making use of it would enhance the readability of the XML string. However, then we can't interpolate variables anymore as multi-line strings are considered verbatim.
The good news is, we don't need to escape quotes with bicep-lang, as opposed to the JSON-based templates.
☝🏼 Did you know? You can transform a multi-line XML document into a single line with VS Code's Join Lines
feature.
One important thing to note is that the ominous hidden-link
tag clues the web test to your Application Insights resource.
If you wonder what the location IDs a referring to have a look at the following table, which I took out of the official documentation.
Display Name | Population Name |
---|---|
Australia East | emea-au-syd-edge |
Brazil South | latam-br-gru-edge |
Central US | us-fl-mia-edge |
East Asia | apac-hk-hkn-azr |
East US | us-va-ash-azr |
France South (Formerly France Central) | emea-ch-zrh-edge |
France Central | emea-fr-pra-edge |
Japan East | apac-jp-kaw-edge |
North Europe | emea-gb-db3-azr |
North Central US | us-il-ch1-azr |
South Central US | us-tx-sn1-azr |
Southeast Asia | apac-sg-sin-azr |
UK West | emea-se-sto-edge |
West Europe | emea-nl-ams-azr |
West US | us-ca-sjc-azr |
UK South | emea-ru-msa-edge |
Standard Test
If you are with me and don't like to fiddle around with embedded XML documents you are going to like the successor to the URL Ping Test.
Here is an example, that does the same as the classic URL Ping Test from above. Every 5 minutes it sends an HTTP GET request to www.azureblue.io and expects a status code 200.
resource standardWebTest 'Microsoft.Insights/webtests@2018-05-01-preview' = {
name: 'demo-webtest'
location: 'westeurope'
tags: {
'hidden-link:/subscriptions/ade29918-737f-497e-8808-4bffda5cc46d/resourceGroups/rg-article/providers/microsoft.insights/components/appi-demo': 'Resource'
}
kind: 'standard'
properties: {
SyntheticMonitorId: 'demo-webtest-id'
Name: 'demo-webtest'
Description: null
Enabled: true
Frequency: 300
Timeout: 120
Kind: 'standard'
RetryEnabled: true
Locations: [
{
Id: 'emea-nl-ams-azr'
}
{
Id: 'emea-ru-msa-edge'
}
{
Id: 'apac-hk-hkn-azr'
}
{
Id: 'latam-br-gru-edge'
}
{
Id: 'emea-au-syd-edge'
}
]
Configuration: null
Request: {
RequestUrl: 'https://www.azureblue.io'
Headers: null
HttpVerb: 'GET'
RequestBody: null
ParseDependentRequests: false
FollowRedirects: null
}
ValidationRules: {
ExpectedHttpStatusCode: 200
IgnoreHttpsStatusCode: false
ContentValidation: null
SSLCheck: true
SSLCertRemainingLifetimeCheck: 7
}
}
}
As you can see, the XML is gone. Also, we get some additional features like TLS certificate validation checks.
Please also note, that I am using the undocumented 2018-05-01-preview
API version. This contradicts the official documentation, which suggests using 2020-10-05-preview
. Following that advice results in an NoRegisteredProviderFound
error.
For once it seems the implementation is lacking behind the documentation and not the other way round 😄
{
"code": "DeploymentFailed",
"message": "At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.",
"details": [
{
"code": "NoRegisteredProviderFound",
"message": "No registered resource provider found for location 'westeurope' and API version '2020-10-05-preview' for type 'webtests'. The supported api-versions are '2014-04-01, 2014-08-01, 2014-12-01-preview, 2015-05-01, 2018-05-01-preview'. The supported locations are ', eastus, southcentralus, northeurope, westeurope, southeastasia, westus2, uksouth, centralindia, canadacentral, japaneast, australiaeast, koreacentral, francecentral, centralus, eastus2, eastasia, westus, southafricanorth, northcentralus, brazilsouth, switzerlandnorth, norwayeast, norwaywest, australiasoutheast, australiacentral2, germanywestcentral, switzerlandwest, uaecentral, ukwest, brazilsoutheast, japanwest, uaenorth, australiacentral, francesouth, southindia, westus3, koreasouth, canadaeast, jioindiawest'."
}
]
}
Feature comparison
Here is a list that compares the classic URL Ping Test to the newer Standard Test
Feature | URL Ping Test (classic) | Standard Test (preview) |
---|---|---|
Check if endpoint is responding | x | x |
Measure time in which endpoint is responding | x | x |
Create alerts based on results | x | x |
SSL Certificate Validiation Checks | x | |
Proactive Lifetime check | x | |
Choose HTTP Request Verb | x | |
Custom Headers | x | |
Custom Data associated with HTTP Request | x |
Summary & Conclusion
- The classic URL Ping Test requires a WebTest XML string, which is undocumented and sucks 🤪
- The successor standard test is still in preview but makes the embedded XML obsolete, which rocks 🤘🏻
- When creating a standard test, you currently need to use the undocumented API version
2018-05-01-preview
instead of2020-10-05-preview
.
I hope this post saved you some headache and as always I'd love to receive feedback! Thanks for reading 😊
Further reading
![](https://docs.microsoft.com/en-us/media/logos/logo-ms-social.png)
![](https://docs.microsoft.com/en-us/media/logos/logo-ms-social.png)