Using Azure to check a website is up - part 2 (internal website)


So following on in quick succession (before I forget what I did) - here are the steps to set up monitoring for an internal website using application insights. The catch here is that you cant do it directly in app insights - instead you have to write something that will exist in your private networking space that will do the test and send the results to the app insights workspace.

In my case I'm sticking with function apps and powershell as for me at least this is the easiest option here.

The actual powershell code doing the test I've 'borrowed' from Niels from his excellent post here : https://swimburger.net/blog/azure/run-availability-tests-using-powershell-and-azure-application-insights

The extra bits I've done are to wrap this in a function app (so its serverless) and deploy that into an 'App Service Environment' (ASE) so it has integration into our private address space.

Niels does a great job of explaining his powershell so I'm not going to even attempt to explain any of that - just refer to his post for more info.

So lets build the function and set up the test

First up we click create new function app - give it a name and choose powershell as the language.


Then we do one of the key steps - when we choose a region we actually have to scroll right to the top and pick our ASE (this post assumes you already have one - if you don't you'll have to sort that part out first). I personally find this screen a little confusing - feels like there should be a radio button for ASE here - putting it in the region drop down feels like its hidden to me.


After we pick the ASE - we can see the public azurewebsites.net name is changed to the internal domain associated with our ASE


We then carry on to the next screen and choose the final couple of options


Pick if we want app insights for this function - now here it is just talking about enabling app insights for the function itself - this doesn't have to be the place we will send data to later (in fact in this example it is to keep it simple but they are different things)


Then we get a summary and go ahead and create it


Once create we need to go and locate the internal ip address it's selected for out function app - you can find this in the screen below


We then have to add 2 records to dns - one for the normal function address and one for the 'scm' (debug) version of the site.

So in my case i add (same ip in both cases)

internalwebtest.mydomain.com 10.x.x.x
internalwebtest.mydomain.com 10.x.x.x

Screen shot below shows adding it for the main address.


Now that's all set up i now need to create the actual function - so I navigate to that blade and add a new one on a timer trigger set to run every 1 minute as you can see below.


Once that's added I then paste in Niels' code - I 've included it here just for completeness but it's essentially unchanged from what Niels posted (other than the function app extras). Note that the app insights workspace it's sending data to is the one the function is pointing at - it picks this directly from the env variable defined in the default function.
# Input bindings are passed in via param block.
param($Timer)

# Get the current universal time in the default string format.
$currentUTCtime = (Get-Date).ToUniversalTime()

# The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled.
if ($Timer.IsPastDue) {
    Write-Host "PowerShell timer is running late!"
}

# Write an information log with the current time.
Write-Host "PowerShell timer trigger function ran! TIME: $currentUTCtime"


#$MyInvocation.MyCommand.Path | Split-Path | Push-Location;

# Update the path if you install a different version of AI NuGet package
#Add-Type -Path .\lib\Microsoft.ApplicationInsights.dll;

$InstrumentationKey = $Env:APPINSIGHTS_INSTRUMENTATIONKEY;
# If your resource is in a region like Azure Government or Azure China, change the endpoint address accordingly.
# Visit https://docs.microsoft.com/azure/azure-monitor/app/custom-endpoints#regions-that-require-endpoint-modification
$EndpointAddress = "https://dc.services.visualstudio.com/v2/track";

$Channel = [Microsoft.ApplicationInsights.Channel.InMemoryChannel]::new();
$Channel.EndpointAddress = $EndpointAddress;
$TelemetryConfiguration = [Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration]::new(
    $InstrumentationKey,  
    $Channel
);
$TelemetryClient = [Microsoft.ApplicationInsights.TelemetryClient]::new($TelemetryConfiguration);

$TestName = "https://internal.website/";
$TestLocation = $Env:COMPUTERNAME; # you can use any string for this
$OperationId = (New-Guid).ToString("N");

$Availability = [Microsoft.ApplicationInsights.DataContracts.AvailabilityTelemetry]::new();
$Availability.Id = $OperationId;
$Availability.Name = $TestName;
$Availability.RunLocation = $TestLocation;
$Availability.Success = $False;

$Stopwatch =  [System.Diagnostics.Stopwatch]::New()
$Stopwatch.Start();

$OriginalErrorActionPreference = $ErrorActionPreference;
Try
{
    $ErrorActionPreference = "Stop";
    # Run test
    $Response = Invoke-WebRequest -Uri "https://internal.website/";
    $Success = $Response.StatusCode -eq 200;
    # End test
    $Availability.Success = $Success;
}
Catch
{
    # Submit Exception details to Application Insights
    $Availability.Message = $_.Exception.Message;
    $ExceptionTelemetry = [Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry]::new($_.Exception);
    $ExceptionTelemetry.Context.Operation.Id = $OperationId;
    $ExceptionTelemetry.Properties["TestName"] = $TestName;
    $ExceptionTelemetry.Properties["TestLocation"] = $TestLocation;
    $TelemetryClient.TrackException($ExceptionTelemetry);
}
Finally
{
    $Stopwatch.Stop();
    $Availability.Duration = $Stopwatch.Elapsed;
    $Availability.Timestamp = [DateTimeOffset]::UtcNow;
    
    # Submit Availability details to Application Insights
    $TelemetryClient.TrackAvailability($Availability);
    # call flush to ensure telemetry is sent
    $TelemetryClient.Flush();
    $ErrorActionPreference = $OriginalErrorActionPreference;
}

To make the code work it needs access to the dll mentioned in Niels' post - I've downloaded that as he explains and now I need to make it available to the app.

To do this I navigate to the Kudu (advanced tools link) from the portal and get the screen below


To authenticate I need the details from the deployment blade - note that the username  you use you don't specify the part before the '/' - so in my case here the username is $internalwebtest


Once authenticated we need to navigate to the folder where out function app code sits and then upload the dll by dragging and dropping from file explorer - see example below.


Now at this point the code should have been working but in my case I got this error:


This is because our cert authority is not one that Microsoft function apps 'trust' - so it doesn't like the cert and throws this error. The fix is to upload the certs into its trusted store so that it will be happy.

I initially tried to upload a combined cert with a root and intermediate cert - this didn't seem to take and was still throwing the error. I then uploaded them separately and it was then fine - you can see the uploaded files below - the only extra part we have to do is explicitly set in the function app code to load these (this seems a little odd as we kind of did this by uploading them didn't we?). Anyway to do this we just need the thumbprint values from the screen below



We then add a new app setting called WEBSITE_LOAD_ROOT_CERTIFICATES and in here paste the thumbprint values (separated by a comma if there is more than one)


So it should look something like this:


Now the script runs without error and we start to see date in app insights - brilliant. You'll see that it looks pretty much the same as for when I demoed this in the last post for a public website - the key difference being there is no edit facility (notice the blank ringed section below) - this is as expected as we are just using this insights workspace to receive the data we create from the function app - we didn't author it in app insights.


So there you go - website monitoring for any internal website(including all those 'legacy' on premises ones - you just need network connectivity to be able to reach then for the test.






Comments