We are creating our API management instance and associated endpoints through Terraform. All our API endpoints (close to a hundred) share the same policy logic for routing the request to an Azure function.
An example policy is like so -
resource "azurerm_api_management_api_operation_policy"
"api_put_policy" {
api_name = azurerm_api_management_api.my_api.name
resource_group_name = azurerm_resource_group.main.name
api_management_name = azurerm_api_management.my_api.name
operation_id = azurerm_api_management_api_operation.my_api.operation_id
xml_content = <<XML
<policies>
<inbound>
<base />
<choose>
<when condition="@(context.Request.Headers.GetValueOrDefault("Key") == "password")">
<set-backend-service base-url="${data.azurerm_function_app.MyFunctionApp.default_hostname}" />
</when>
<when condition="@(context.Request.Headers.GetValueOrDefault("Key") != null)">
<return-response>
<set-status code="400" reason="Bad Request" />
<set-body>An incorrect Key header has been passed in the request</set-body>
</return-response>
</when>
<otherwise>
<set-backend-service base-url="${other-route-variable}" />
</otherwise>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
So we have the same XML_content being used on every API endpoint, only the variables get set differently depending what function app is going to be routed to.
Is there a way this xml content could be moved into a file where parameters can be passed through to then generate the XML for every API policy so we have the logic stored in only one place?
I have looked at a variety of uses of the file() function but can't see anything that could be done to achieve what I need here.
Thanks
Yes, you can use the templatefile
function for that [1]. The templatefile
function works in the following way:
templatefile(path, vars)
Where the path
represents the file location and the vars
are a map of variables that will be used to replace the placeholders in the file itself. I will give an example based on the XML file you have. You would first create the template file inside of the same directory probably (e.g., xml_content.tpl
):
<policies>
<inbound>
<base />
<choose>
<when condition="@(context.Request.Headers.GetValueOrDefault("Key") == ${password})">
<set-backend-service base-url="${hostname_url}" />
</when>
<when condition="@(context.Request.Headers.GetValueOrDefault("Key") != null)">
<return-response>
<set-status code="400" reason="Bad Request" />
<set-body>An incorrect Key header has been passed in the request</set-body>
</return-response>
</when>
<otherwise>
<set-backend-service base-url="${other-route-variable}" />
</otherwise>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
Notice that I removed the password
value and the data source output in url
. Those will now expect variables with names password
and hostname_url
to be provided when using the templatefile
function:
resource "azurerm_api_management_api_operation_policy" "api_put_policy" {
api_name = azurerm_api_management_api.my_api.name
resource_group_name = azurerm_resource_group.main.name
api_management_name = azurerm_api_management.my_api.name
operation_id = azurerm_api_management_api_operation.my_api.operation_id
xml_content = templatefile("${path.root}/xml_content.tpl",
password = var.password
hostname_url = data.azurerm_function_app.MyFunctionApp.default_hostname
)
}
Whenever this is called, it will look for the placeholder values and replace them. Two additional things to note:
With the current setup, the "${other-route-variable}"
would be required to be provided in the templatefile
function call, otherwise it would fail.
The path.root
option is built-in in Terraform [2].
In theory, if you were to create a module from this to make it more portable, then you would just have to change the path
to the file so it can be provided through a variable probably.
[1] https://www.terraform.io/language/functions/templatefile
[2] https://www.terraform.io/language/expressions/references#filesystem-and-workspace-info