Azure Verified Modules with only AzAPI
Can you make a verified module with only AzAPI?
In this post, I’m going to illustrate a thought experiment:
Can we entirely remove the AzureRM provider from an Azure Verified Module (AVM) resource module?
Most specifically, we’re going to take a module that is largely written using AzAPI (the virtual network module), and illustrate an easy way to do the common last-mile items like the shared interfaces
As a reminder, the shared interfaces for the vnet module means:
- role assignments,
- diagnostic settings,
- & locks
In the AVM template, these all use AzureRM.
In a previous post I wrote about using AzAPI to manage role assignments, as I discussed this work with the AVM team, I learnt about something new… utility modules.
Utility Modules
If you’ve been following AVM, you’ll doubtless know about resource modules and pattern modules, but what’s a utility module?!
The spec says it:
…implements a function or routine that can be flexibly reused in resource or pattern modules - e.g., a function that retrieves the endpoint of an API or portal of a given environment. It MUST NOT deploy any Azure resources other than deployment scripts.
This might seem a bit counter-intuitive, a module that doesn’t deploy anything?
What is this trickery?!
As it turns out, utility modules are very useful for encapsulating logic that is needed across many resources. Every resource must support all the standard interfaces, an ideal use case for flexible re-use, hence this creation from Matt White:
https://github.com/Azure/terraform-azure-avm-utl-interfaces
Its purpose is to make it easier to support the standard interfaces.
Using the interface utility module
Calling the utility module is done like this:
|
|
The “vars” on the right-hand side are just the required variable blocks defined in the specification, as you get from the AVM template.
The utility module returns maps as outputs which can then be used to make the components:
|
|
The returned map makes this very easy to use, you just need to assign the type + the body.
Similarly, here’s the lock - there’s only 0 or 1 of these, so we’ll use a count:
|
|
The interfaces module also includes support for the other standard interfaces, such as private endpoints and customer managed keys.
Helping migration with moved()
Since we’re moving resources from AzureRM to AzAPI, we also need our good friend, the moved block, to avoid resources being destroyed and re-created.
|
|
If you’re not aware of this trick, check out one of my (surprisingly popular!) posts on moving resources from AzureRM to AzAPI from a few months back.
Interested in the end result?
If you’d like to see the result, I have this as an experimental PR on the virtual network module.
It is worth pointing out that just because a module is written in AzAPI, it doesn’t preclude the calling code from being based in AzureRM. Most of the examples that test the module use simple resources defined this way.
To put the cherry on the cake, I also wrote a pure AzAPI example to illustrate how this could be called with related resources all using AzAPI.
Links may change
Since this is on a feature branch - some of the above code links may change, if you’re coming to this later - please drop me a note in the comments and I’ll update them if I can!
Call to action
If you’re looking at converting modules to AzAPI, or using AzAPI for an AVM module, please take advantage of the new utility module to standardise & simplify how to make the shared interfaces!