Azure Logic Apps, tips from the real world
About 2 years ago I wrote some PowerShell as a workflow function that could be used in Azure Automation. The purpose was simple, get a daily email informing me of yesterdays Azure spend and then predict my annual charge based on it. I had a colleague ask me about it, and it got me thinking – pretty much the entirety of my script could be replicated in an Azure Logic App. Here’s the script if you’re interested : http://gordon.byers.me/azure/estimating-your-annual-azure-bill/
Translating the PowerShell function into a Logic App wouldn’t really add much value to the end product, i’d still get an email… However it would be a good experience for eating the Logic App dog food and seeing where the capabilities fall short and I have to use some code. It also makes it very easy to customise with other connectors in the Logic Apps library. To that end, this post isn’t so much about Azure billing, but Logic Apps and the tips and tweaks that you might find useful when considering it for your own workloads.
So, lets start with the end result, then pick it apart.
- The Trigger. A schedule. Once every day at approx. 9am.
- Initialise Variable. Setting an integer variable to the value for my Azure Enterprise Enrolment.
- Initialise Variable. Setting a string variable to the value for my EA Billing API key. (Ok, i’m cheating here as at the time Logic Apps doesn’t have string variables, but it’s coming soon!)
- Http call. Doing a GET to the EA billing api and asking for a summary of all usage reports.
- Blob create. Persisting the Summarised data from the api down to a container for future analysis
- Parse Json. Looking to what was returned in the Http call, and putting a Json Schema over the top to allow me to use this data in further Logic Apps.
- Parse Json. Filtering to the last month in the Array and putting a Json Schema over the top of it
- Blob create. Persisting the output to blob storage purely as part of the development process, so I can see what’s going on
- Http call. Doing a secondary GET to the EA billing api and asking for the detailed usage for the latest month
- Blob create. Persisting the detailed data down to blob storage for future analysis
- Azure function. At this point I need something to take a CSV file, clean it up a little, do some maths and just return me the sum of my usage in a currency unit
- Blob create. Persisting the output to blob storage purely as part of the development process, so I can see what’s going on
- Gmail send. Sending an HTML email with the monthly cost and predicted cost
So as it stands I managed to get quite far through the process without reaching out to Azure Functions. When I did have to use my own code, I created a Powershell Azure Function which let me keep all my previously written code for parsing…. RESULT! Nothing worse than rewriting something that works.
Here’s how that code looks;
$requestBody = Get-Content $req -Raw | ConvertFrom-Json $mContent = ($requestBody.csv -split '[\r\n]') $monthBill = $mContent | Where-Object -FilterScript { [regex]::matches($_,",").count -gt 28} | ConvertFrom-Csv $filterDay =$monthBill[-1].Date $aday = $monthBill | Where-Object -FilterScript {$_.date -eq $filterDay} $adayCost = [math]::round($($aday | Select-Object -ExpandProperty ExtendedCost | Measure-Object -Sum).sum,2) Out-File -Encoding Ascii -FilePath $res -inputObject $adayCost
Tips and Tricks
Ok, so it wasn’t all plain sailing writing the logic app. Here’s a few areas where I needed to do more than connect the dots with the visual designer.
Parsing Json
These are really cool little actions. They let you put a JSON schema on top of an Json that you’ve taken into the Logic App. Previously you’d have multiple Logic Apps talking to each other over Request/Response triggers. For ultimate ease, they’ll create the schema for you based on the json data, so make sure you’ve got this to hand. I found that using the Run History UI in Logic Apps pretty handy, as was persisting it down to blob storage and then grabbing it out.
Filtering to the last item in an array
Using a Json Parse action worked well again here, and allowed me to use the LAST function to quickly focus on what I wanted.
**
Concatenating implicitly in an Http action’s URI field**
Ok, it didn’t like this much at all. I had to break into code mode and use the CONCAT function to combine the base URL with the one resulted from the HTTP call.
@{concat('https://ea.azure.com/',body('Grab Latest Months Summary')?['LinkToDownloadDetailReport'])}
Wrapping the output in Json
An easy one, but one worth mentioning, when passing data around between functions and API’s you’ll often have to start wrapping it in JSON.
Type conversion and maths
My PowerShell function returns a string, which I then need to convert to an integer and do some basic maths on.
I used MUL to perform a multiplication, and FLOAT to convert the string to a float that I could do the MUL on.
You spent £@{body('Parse-Azure-EA-Detail-CSV')} yesterday. <br /> If every day was like yesterday, your 12 monthly Azure Consumption would be £@{mul(365,float(body('Parse-Azure-EA-Detail-CSV')))} <br />
I’ll be creating an ARM template for this and putting it on GitHub soon, so if you’re wanting to get a daily email with your Azure spend you’ll be able to quickly and easily.