ARM Template API Management Deploy PolicyContent - azure

I am trying to use ARM templates to deploy my API management service and have everything working except policyContent. Basically it wants the policyContent as "Json escaped Xml Encoded contents of the Policy." This is very hard to maintain and was trying to find a way to take an XML file and inject the contents into this string, or some better way. I would like not to have to write a program to maintain these strings because it feels like something that shouldn't be so complicated.
Policy Reference
Example with string
{
"name": "policy",
"type": "Microsoft.ApiManagement/service/apis/policies",
"apiVersion": "2017-03-01",
"properties": {
"policyContent": "string"
}
}

You can maintain your policies into an XML file and reference it like this:
{
"apiVersion": "2018-01-01",
"name": "policy",
"type": "Microsoft.ApiManagement/service/policies",
"properties": {
"policyContent": "[concat(parameters('repoBaseUrl'), '/policy.xml')]",
"contentFormat": "rawxml-link"
},
"dependsOn": [
"[resourceId('Microsoft.ApiManagement/service/', parameters('ApimServiceName'))]"
]
}
Your policy.xml file must be available online and will look like this:
<policies>
<inbound>
<rate-limit calls="3" renewal-period="10" />
<base />
</inbound>
<outbound>
<base />
</outbound>
<backend>
<base />
</backend>
<on-error>
<base />
</on-error>
</policies>

Well, the only thing I can think of (because nothing native in arm templates can help you) is read the input from a file and convert it to JSON:
$xml = (Get-Content file -Raw).ToString()
($xml | ConvertTo-Json -Compress) -replace '\\u003c','<' ) -replace '\\u003e','>'
It might work without replacing those unicodes back to <>, no idea.

Related

manipulate response in apim outbound policies

I have SOAP service that I have converted to rest in apim and returns the response in json using the following outbound policy:
<outbound>
<base />
<xml-to-json kind="direct" apply="always" consider-accept-header="false" />
</outbound>
Response output is like below:
"response": {"currentABNRecord": {
"ABN":
{
"identifierValue": "xxxxx",
"identifierStatusCode": "ACT",
"issuingPartyCode": null,
"replacedIndicator": "N"
}
}
}
My requirement is to "manipulate" conditionally data by modifying "identifierStatusCode" and appending a new attribute "termsAnConditions" when "identifierStatusCode" is "ACT" and if it is DEL to "DELETED" to something else like below :
"response": {"currentABNRecord": {
"ABN":
{
"identifierValue": "xxxxx",
"identifierStatusCode": "ACT",
"issuingPartyCode": null,
"replacedIndicator": "N",
"termsAnConditions": "Some terms and conditions"
}
}
}
How can I call an azure function(perform all the conditional logic in it ) in the outbound policy and return the modified object. Is this the correct approach or can I do it policies.

Validation Error in APIM Policy for Websocket

I am trying to add policy to the websocket endpoint in Azure API Management through ARM template but I am getting error
"error": {
"code": "ValidationError",
"message": "Not allowed at 'Api' scope for 'WEBSOCKET' api type"
}
I am able to add the policy manually, but I am unable to add the policy to web socket through ARM template. I have tried the same policy to web api its successful.
ARM template for just policy I was trying to see if it can be deployed after the websocket is provisioned:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"ApimServiceName": {
"type": "String"
},
"policypath": {
"type": "String"
},
"Environment": {
"type": "String"
},
},
"variables": {
"env": "[concat('test-', parameters('Environment'))]",
"svc": "[concat('testsvc-', parameters('Environment'))]"
},
"resources": [
{
"type": "Microsoft.ApiManagement/service/apis/policies",
"apiVersion": "2022-04-01-preview",
"name": "[concat(parameters('ApimServiceName'), '/', variables('env'), '/policy')]",
"dependsOn": [],
"properties": {
"value": "[parameters('policypath')]",
"format": "rawxml-link"
}
}
]
}
entire arm template which I used to deploy both websocket and policy is here(I have tried to directly add the policy instead of sas link for policy).
I am able to figure out a workaround, when I directly add the policy to the operation it works. even then, I have to write the policy directly in the same file the arm template way of providing the file with SAS is not working. here is the current version of code.
{
"properties": {
"value": "<!--\r\n IMPORTANT:\r\n - Policy elements can appear only within the <inbound>, <outbound>, <backend> section elements.\r\n - To apply a policy to the incoming request (before it is forwarded to the backend service), place a corresponding policy element within the <inbound> section element.\r\n - To apply a policy to the outgoing response (before it is sent back to the caller), place a corresponding policy element within the <outbound> section element.\r\n - To add a policy, place the cursor at the desired insertion point and select a policy from the sidebar.\r\n - To remove a policy, delete the corresponding policy statement from the policy document.\r\n - Position the <base> element within a section element to inherit all policies from the corresponding section element in the enclosing scope.\r\n - Remove the <base> element to prevent inheriting policies from the corresponding section element in the enclosing scope.\r\n - Policies are applied in the order of their appearance, from the top down.\r\n - Comments within policy elements are not supported and may disappear. Place your comments between policy elements or at a higher level scope.\r\n-->\r\n<policies>\r\n <inbound>\r\n <base />\r\n </inbound>\r\n <backend>\r\n <retry condition=\"#(context.Response.StatusCode >= 400)\" count=\"2\" interval=\"1\" first-fast-retry=\"true\">\r\n <choose>\r\n <when condition=\"#(context.Response != null && context.Response.StatusCode >= 400)\">\r\n <set-backend-service base-url=\"wss://\" />\r\n </when>\r\n <otherwise />\r\n </choose>\r\n <forward-request />\r\n </retry>\r\n </backend>\r\n <outbound>\r\n <base />\r\n </outbound>\r\n <on-error>\r\n <base />\r\n </on-error>\r\n</policies>",
"format": "xml"
},
"type": "Microsoft.ApiManagement/service/apis/operations/policies",
"apiVersion": "2022-04-01-preview",
"name": "[concat(parameters('ApimServiceName'), '/', variables('env'), '/onHandshake/policy')]",
"dependsOn": [
"[resourceId('Microsoft.ApiManagement/service/apis', parameters('ApimServiceName'), variables('env'))]"
]
},

Azure App Insights with web test, - ERROR: a single hiding link tag pointing to AI resource is required

I am trying to create a template for App Insights web availability
tests. I am using bicep, and this is my template:
param location string = resourceGroup().location
param pingText string = ''
param appInsightsResource string
param tests array
resource tests_0_name 'Microsoft.Insights/webtests#2015-05-01' = {
name: tests[0].name
location: location
tags: {
'hidden-link:${appInsightsResource}': 'Resource'
}
properties: {
Name: tests[0].name
Description: tests[0].description
Enabled: true
Frequency: tests[0].frequency_secs
Timeout: tests[0].timeout_secs
Kind: 'ping'
Locations: tests[0].locations
Configuration: {
WebTest: '<WebTest Name="${tests[0].name}" Enabled="True" CssProjectStructure="" CssIteration="" Timeout="120" WorkItemIds="" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010" Description="" CredentialUserName="" CredentialPassword="" PreAuthenticate="True" Proxy="default" StopOnError="False" RecordedResultFile="" ResultsLocale=""> <Items> <Request Method="GET" Version="1.1" Url="${tests[0].url}" ThinkTime="0" Timeout="300" ParseDependentRequests="True" FollowRedirects="True" RecordResult="True" Cache="False" ResponseTimeGoal="0" Encoding="utf-8" ExpectedHttpStatusCode="${tests[0].expected}" ExpectedResponseUrl="" ReportingName="" IgnoreHttpStatusCode="False" /> </Items> <ValidationRules> <ValidationRule Classname="Microsoft.VisualStudio.TestTools.WebTesting.Rules.ValidationRuleFindText, Microsoft.VisualStudio.QualityTools.WebTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" DisplayName="Find Text" Description="Verifies the existence of the specified text in the response." Level="High" ExecutionOrder="BeforeDependents"> <RuleParameters> <RuleParameter Name="FindText" Value="${pingText}" /> <RuleParameter Name="IgnoreCase" Value="False" /> <RuleParameter Name="UseRegularExpression" Value="False" /> <RuleParameter Name="PassIfTextFound" Value="True" /> </RuleParameters> </ValidationRule> </ValidationRules> </WebTest>'
}
SyntheticMonitorId: tests[0].name
}
}
and also a parameters file:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appInsightsResource": {
"value": "myappinsight"
},
"tests": {
"value": [
{
"name": "5121",
"url": "http://www.microsoft.com",
"expected": 200,
"frequency_secs": 300,
"timeout_secs": 30,
"failedLocationCount": 1,
"description": "a description for test1",
"guid": "5122",
"locations": [
{
"Id": "us-il-ch1-azr"
}
]
},
{
"name": "1242",
"url": "http://www.microsoft.com",
"expected": 404,
"frequency_secs": 300,
"timeout_secs": 30,
"failedLocationCount": 1,
"description": "a description for test3",
"guid": "5211",
"locations": [
{
"Id": "us-il-ch1-azr"
}
]
}
]
}
}
}
The problem is that, when I create this I get an error {"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.","details":[{"code":"BadRequest","message":"A single 'hidden-link' tag pointing to an existing AI component is required. Found none."}]}
"A single 'hidden-link' tag pointing to an existing AI component is required. Found none.
As you can see, I have a tag with hidden link, but Azure points to my tests, which I suppose do not have this tags, I don't know how to add them or what do to to make this work.
While adding tags to resources we have some limitations. I have noticed that in your Bicep template you are using Special Character -.
hidden-link:${appInsightsResource}'
Some Special Characters are not supported those are <, >, %, &, \, ?, /,-.
I have modified your code like below:
resource tests_0_name 'Microsoft.Insights/webtests#2015-05-01' = {
name: tests[0].name
location: location
tags: {
# While adding tags remove the special charactor
'hiddenlink:${appInsightsResource}': 'Resource'
}
I have tried from my end The result follows:
Bicep File
Json Result
Tag added in the Resource
References
MS-DOC for Tag Limitation
MS-DOC for Supported Resources

Azure API management - how to access product information

In APIM, I am trying to access the Product information at API level policy, as i have to execute some logic based on product name. I am using the below code
<policies>
<inbound>
<set-variable name="ProductName" value="#{
return context.Product.Name;
}" />
But, when trying to post request from postman, i can see the below exception in trace.
{
source: "set-variable",
timestamp: "2020-08-19T14:42:24.4936554Z",
elapsed: "00:00:00.0358409",
data:- {
messages:- [
-{
message: "Expression evaluation failed.",
expression: " return context.Product.Name; ",
details: "Object reference not set to an instance of an object."
},
"Expression evaluation failed. Object reference not set to an instance of an object.",
"Object reference not set to an instance of an object."
]
}
}
Why it is null ? is this the case, that i can't access the property in inbound scope. Need guidance. Or, is there any other way i can access the Product.Name property.
Thank you.
You can get the Product Name with #(context.Product.Name).
<inbound>
<base />
<set-variable name="aaa" value="#(context.Product.Name)" />
<set-body template="liquid">
{
"success": true,
"var1": {{context.Variables["aaa"]}}
}
</set-body>
</inbound>
In test, set the product name as Starter and you will get the snapshot as below.

Policy rewrite-uri To Append Context Variable in Azure APIM

What is the approach to a simple append to the url of a context variable such as context.Variables["accountKey"] during a policy rewrite?
The end result should be /accounts/232.
I have success earlier in setting it
set-variable (0.003 ms)
{
"message": "Context variable was successfully set.",
"name": "accountKey",
"value": "232"
}
One of the things tried:
<policies>
<inbound>
<base />
<rewrite-uri template="/accounts/{accountKey}" />
</inbound>
But I get this error
> Error Receive
> rewrite-uri (0.260 ms) {
> "messages": [
> null,
> "Variable accountKey has no value.",
> "Variable accountKey has no value."
> ] }
Configure the inbound rule in the policy as follows:
<inbound>
<base />
<set-variable name="accountKey" value="232" />
<rewrite-uri template="#{
return "/account/" + context.Variables.GetValueOrDefault<string>("accountKey");
}"/>
</inbound>
{} in rewrite-uri are for query string parameters in the original request URL.
Find more details about rewrite-uri section in the Microsoft docs at Rewrite URL - API Management transformation policies.
I ended up using this call as shown as an alternative:
<rewrite-uri template="#($"/account/{(string)context.Variables["accountKey"]}/")" />
In my case, my URL was
https://test.com/send/
I need to add query string from context variable name (name = myName)
https://test.com/send/myName
This is working for me:
<rewrite-uri template="#($"{(string)context.Variables["name"]}")" />

Resources