terraform-provider-azapi
terraform-provider-azapi copied to clipboard
`azapi_resource` for Policy Fragments yielding constant diff with `rawxml` submissions
We're getting constant diffs when submitting policy fragments via the following resource block:
resource "azapi_resource" "api" {
for_each = local.files
type = var.type
name = each.key
parent_id = var.parent_id
ignore_casing = true
ignore_missing_property = true
schema_validation_enabled = false
body = jsonencode({
properties = {
description = each.key
format = "rawxml"
value = templatefile(each.value, {
subscription_id = var.subscription_id
resource_group_name = var.resource_group_name
})
}
})
lifecycle {
create_before_destroy = true
}
}
Here is a sample policy we submit as a rawxml fragment:
<fragment>
<set-variable name="UserId" value="@{
return ((Jwt)context.Variables["jwt"]).Claims.GetValueOrDefault("sub", new string[1]).First();
}" />
<set-body>@{
var userId = context.Variables.GetValueOrDefault<string>("UserId", "");
JObject inBody = context.Request.Body?.As<JObject>();
if (inBody != null) {
inBody.Add("user_id", userId);
}
return inBody.ToString();
}</set-body>
</fragment>
Here is the output from the Terraform plan (after an apply):
<fragment>\r\n\t<set-variable name=\"UserId\" value=\"@{
 return ((Jwt)context.Variables["jwt"]).Claims.GetValueOrDefault("sub", new string[1]).First();
 }\" />\r\n\t<set-body>@{\r\n var userId = context.Variables.GetValueOrDefault<string>(\"UserId\", \"\");\r\n JObject inBody = context.Request.Body?.As<JObject>();\r\n if (inBody != null) {\r\n inBody.Add(\"user_id\", userId);\r\n }\r\n return inBody.ToString();\r\n }</set-body>\r\n</fragment>
Here is the same output from a GET request directly against the REST api with properties: https://management.azure.com/subscriptions/{{SUBSCRIPTION_ID}}/resourceGroups/{{RESOURCE_GROUP}}/providers/Microsoft.ApiManagement/service/{{SERVICE_NAME}}/policyFragments/:policyFragmentName?api-version=2022-08-01&format=rawxml and response:
<fragment>\r\n\t<set-variable name=\"UserId\" value=\"@{\n return ((Jwt)context.Variables[\"jwt\"]).Claims.GetValueOrDefault(\"sub\", new string[1]).First();\n }\" />\r\n\t<set-body>@{\n var userId = context.Variables.GetValueOrDefault<string>(\"UserId\", \"\");\n JObject inBody = context.Request.Body?.As<JObject>();\n if (inBody != null) {\n inBody.Add(\"user_id\", userId);\n }\n return inBody.ToString();\n }</set-body>\r\n</fragment>
and the xml response:
<fragment>\r\n\t<set-variable name=\"UserId\" value=\"@{
 return ((Jwt)context.Variables["jwt"]).Claims.GetValueOrDefault("sub", new string[1]).First();
 }\" />\r\n\t<set-body>@{\r\n var userId = context.Variables.GetValueOrDefault<string>(\"UserId\", \"\");\r\n JObject inBody = context.Request.Body?.As<JObject>();\r\n if (inBody != null) {\r\n inBody.Add(\"user_id\", userId);\r\n }\r\n return inBody.ToString();\r\n }</set-body>\r\n</fragment>
and the raw state body looks like this:
{\"properties\":{\"description\":\"append-userId-to-body\",\"format\":\"rawxml\",\"value\":\"\\u003cfragment\\u003e\\r\\n\\t\\u003cset-variable name=\\\"UserId\\\" value=\\\"@{\\u0026#xA; return ((Jwt)context.Variables[\\u0026quot;jwt\\u0026quot;]).Claims.GetValueOrDefault(\\u0026quot;sub\\u0026quot;, new string[1]).First();\\u0026#xA; }\\\" /\\u003e\\r\\n\\t\\u003cset-body\\u003e@{\\r\\n var userId = context.Variables.GetValueOrDefault\\u0026lt;string\\u0026gt;(\\\"UserId\\\", \\\"\\\");\\r\\n JObject inBody = context.Request.Body?.As\\u0026lt;JObject\\u0026gt;();\\r\\n if (inBody != null) {\\r\\n inBody.Add(\\\"user_id\\\", userId);\\r\\n }\\r\\n return inBody.ToString();\\r\\n }\\u003c/set-body\\u003e\\r\\n\\u003c/fragment\\u003e\"}}
That looks like a mix of encodings and escape sequences (JSON, Unicode, XML, HTML, and special chars).
Hi @PrestonR ,
Thank you for taking time to report this issue and provide the details!
It seems that the API doesn't return the value as the payload. This should be an upstream-api bug.
I have a workaround, it uses azapi_resource_action to create the policy fragment, but please notice deleting the azapi_resource_action will not remove the policy fragment:
resource "azapi_resource_action" "put_policyFragment" {
type = "Microsoft.ApiManagement/service/policyFragments@2023-03-01-preview"
resource_id = "${azapi_resource.service.id}/policyFragments/henglu001"
method = "PUT"
body = jsonencode({
properties = {
description = "some description"
format = "rawxml"
value = local.input
}
})
}
I've created an issue to track it: https://github.com/Azure/azure-rest-api-specs/issues/25306
@ms-henglu is there any update on this?
Hi @travisgan , sorry for late response. It seems there's no updates on the API side. Would you please try the above workaround?