Add Url Rule to Azure Application Gateway from a different ARM template - azure

I have an resource group ARM template that I use to create an application gateway that is configured for url routing. It sends traffic to different Web Apps in that resource group based on url path rules. I deploy the base resource group ARM template, and then each web app has its own ARM template that setups a Web App on an App Service Plan. I am trying to figure out how to add a rule to an existing Url Path Map on an Application Gateway without defining the whole application gateway in every template. This way, I can simply add web apps and have them "register" on to the application gateway with a particular path rule.
I considered doing a linked template where my base template would have all of the shared resources (databases, app service plan, and app gateway), but even with a linked template, I don't think I can add a rule to the application gateway.
Update
So I modified my template by adding a reference to the existing application gateway, and then adding variables for the new BackEndPoolAddress and new Path Rule. It ends up like this (abbreviated to only relevant parts):
"variables": {
"appGateway": "[reference(concat('Microsoft.Network/applicationGateways/', 'appGateWay-', uniqueString(resourceGroup().id)), '2017-06-01')]",
"pathRule": {
"name": "[concat(parameters('websiteName'), '- RoutingRule')]",
"properties": {
"paths": [
"[parameters('routingRule')]"
],
"backendAddressPool": {
"id": "[concat(variables('appGateway').id, '/backendAddressPools/',parameters('websiteName'), 'BackEndPool')]"
},
"backendHttpSettings": {
"id": "[variables('appGateway').backendHttpSettingsCollection[0]]"
}
}
},
"backendPool": {
"name": "[concat(parameters('websiteName'), 'BackEndPool')]",
"properties": {
"IpAddress": "[reference(variables('webSiteName')).defaultHostName]"
}
}
},
"resources": [
...
{
"apiVersion": "2017-06-01",
"name": "[variables('appGateway').name]",
"type": "Microsoft.Network/applicationGateways",
"location": "[resourceGroup().location]",
"properties": {
"backendAddressPools": "[concat(variables('appGateway').backendAddressPools, variables('backendPool'))]",
"urlPathMaps": [
{
"name": "[variables('appGateway').urlPathMaps[0]]",
"pathRules": "[concat(variables('appGateway').urlPathMaps[0].pathRules, variables('pathRule'))]"
}
]
}
}
],
However I get a template validation error saying I can't use the Reference function in the Variables section. If I don't add it in the variables section, how can I build the correct paths for the pool and pathRule in my variables section?

you can achieve this using the reference() function, array manipulation and nested templates (might work even without those, worst case you will need them). example:
"outputs": {
"httpListeners": {
"type": "array",
"value": "[reference('application_gateway_id', '2018-08-01', 'Full').properties.httpListeners]"
}
}
Will return you array or httpListeners. you can get all the relevant application gateway properties and add new (additional) properties with the concat() and assign the result to the property (properties):
"httpListeners": "[concat(reference('application_gateway_id', '2018-08-01', 'Full').properties.httpListeners, variables('newListener'))]"
you just need to make sure 2 deployments dont start at the same time, one might overwrite the other

Here is the solution I finally ended up with using the Azure CLI. This script is idempotent and runs during my release process.
echo "Logging into AKS Cluster"
az aks get-credentials --resource-group $RESOURCEGROUP_NAME --name $AKSNAME
echo "Get the created service's ip address"
SERVICEIP=$(kubectl get service --namespace $AKSNAMESPACE $APPNAME-service -o jsonpath="{.status.loadBalancer.ingress[0].ip}")
echo "Creating backend pool - IP $SERVICEIP"
az network application-gateway address-pool create \
--gateway-name $APPGATEWAYNAME \
--resource-group $RESOURCEGROUP_NAME \
--name "$APPNAME-pool" \
--servers $SERVICEIP
echo "Creating probe"
az network application-gateway probe create \
--gateway-name $APPGATEWAYNAME \
--name "$APPNAME-probe" \
--path $APPPROBE \
--resource-group $RESOURCEGROUP_NAME \
--protocol Http \
--resource-group $RESOURCEGROUP_NAME \
--host-name-from-http-settings true
echo "Creating HTTP Settings"
az network application-gateway http-settings create \
--gateway-name $APPGATEWAYNAME \
--name "$APPNAME-settings" \
--port 80 \
--resource-group $RESOURCEGROUP_NAME \
--host-name-from-backend-pool \
--probe "$APPNAME-probe" \
--protocol Http
echo "Creating URL Path Map"
az network application-gateway url-path-map rule create \
--gateway-name $APPGATEWAYNAME \
--name "$APPNAME-rule" \
--paths $RULEPATH \
--path-map-name $RULENAME \
--resource-group $RESOURCEGROUP_NAME \
--http-settings "$APPNAME-settings" \
--address-pool "$APPNAME-pool"

Related

Create azure virtual machine with image Flexify.io with command

I can create a virtual machine with the UI :
via Azure marketplace with Flexify.io, however, I want to use the command since I want the VM to be created when it's secured (SSL).
These are the image for Flexify.io :
https://hub.docker.com/r/flexifyio/ce/tags
So I tried to use the command below :
az vm create --resource-group myresourcegroups --name staging-images --image flexifyio/ce:latest --admin-username azureuser --generate-ssh-keys --custom-data ~/Documents/cloud-init-web-server.txt --secrets "$vm_secret"
This is the flexify.io image flexifyio/ce:latest, but am getting this error :
Invalid image "flexifyio/ce:latest". Use a valid image URN, custom image name, custom image id, VHD blob URI, or pick an image from ['CentOS', 'Debian', 'Flatcar', 'openSUSE-Leap', 'RHEL', 'SLES', 'UbuntuLTS', 'Win2022Datacenter', 'Win2022AzureEditionCore', 'Win2019Datacenter', 'Win2016Datacenter', 'Win2012R2Datacenter', 'Win2012Datacenter', 'Win2008R2SP1'].
See VM create -h for more information on specifying an image.
How best can I do this?
The --image argument for az vm commands can be used to reference an image available on the Azure Marketplace, not Docker Hub (or any other repository, for that matter). Azure Marketplace is also the source of the images you see in the VM creation flow in the Azure Portal.
To find the identifier for the image you want to create your VM with, use az vm image list --all --publisher Flexify, which yields some results:
[
{
"architecture": "x64",
"offer": "migration-vm",
"publisher": "flexify-io",
"sku": "migration-vm-ce",
"urn": "flexify-io:migration-vm:migration-vm-ce:2.12.10",
"version": "2.12.10"
},
{
"architecture": "x64",
"offer": "multi-cloud",
"publisher": "flexify-io",
"sku": "multi-cloud-vm-ce",
"urn": "flexify-io:multi-cloud:multi-cloud-vm-ce:2.12.0",
"version": "2.12.0"
},
{
"architecture": "x64",
"offer": "multi-cloud",
"publisher": "flexify-io",
"sku": "multi-cloud-vm-ce",
"urn": "flexify-io:multi-cloud:multi-cloud-vm-ce:2.12.2",
"version": "2.12.2"
},
{
"architecture": "x64",
"offer": "single-vm",
"publisher": "flexify-io",
"sku": "single-vm-ce",
"urn": "flexify-io:single-vm:single-vm-ce:2.12.10",
"version": "2.12.10"
}
]
Then pass the urn value of the image you want to deploy to your VM like so:
az vm create --resource-group myresourcegroups --name staging-images --image flexify-io:single-vm:single-vm-ce:2.12.10 --admin-username azureuser --generate-ssh-keys --custom-data ~/Documents/cloud-init-web-server.txt --secrets "$vm_secret"

How can I deploy a prepackaged Quarkus Azure Functions app

Quarkus Azure function apps currently rely on the Maven azure-functions-maven-plugin plugin to perform a deployment of the function. However, this means that I need to package the application source code and rebuild it with each deployment. This is not ideal, as I really want an immutable package that I can deploy, promote, and roll back without rebuilding.
Is there any way to deploy a prepackaged Quarkus app without the Maven plugin?
The reality is that Microsoft has done a poor job of supporting Java developers deploying to Azure functions. The requirement to recompile the app with each deployment, which is the only option available to you when using the Maven plugin, is an anti-pattern for repeatable and reliable deployments.
Digging through the source code of the Maven plugin eventually leads you to the RunFromBlobFunctionDeployHandler class, which uploads a ZIP file as a blob, creates a long lived SAS token, and then sets the WEBSITE_RUN_FROM_PACKAGE setting to the SAS URL.
To recreate this process, we first need a function.json file, which will redirect all requests to the Quarkus io.quarkus.azure.functions.resteasy.runtime.Function.run class. You can get this class by generating a sample Quarkus project, as documented here:
{
"scriptFile" : "../products-microservice-runner.jar",
"entryPoint" : "io.quarkus.azure.functions.resteasy.runtime.Function.run",
"bindings" : [ {
"type" : "httpTrigger",
"direction" : "in",
"name" : "req",
"route" : "{*path}",
"methods" : [ "GET", "POST", "HEAD", "PUT", "OPTIONS", "DELETE" ],
"dataType" : "binary",
"authLevel" : "ANONYMOUS"
}, {
"type" : "http",
"direction" : "out",
"name" : "$return"
} ]
}
You then need a host.json file, again generated by the sample Quarkus project:
{
"version": "2.0"
}
Once we build your Quarkus Azure function app, you'll have a self contained JAR file. In my case it was called products-microservice-runner.jar. The next step is to recreate the directory structure documented here:
rm -rf /tmp/octopubproductservice
mkdir /tmp/octopubproductservice
mkdir /tmp/octopubproductservice/octopubproductservice
cp target/products-microservice-runner.jar /tmp/octopubproductservice
cp azure-config/host.json /tmp/octopubproductservice
cp azure-config/function.json /tmp/octopubproductservice/octopubproductservice
pushd /tmp/octopubproductservice
zip -r $ZIP_FILE .
popd
This produces a ZIP file like this:
Now create the resource group, storage account, and function as documented here:
REGION=australiaeast
RESOURCE_GROUP=octopubproductservice
FUNCTION_NAME=octopubproductservice
STORAGE_ACCOUNT=octopubproductservice
STORAGE_SKU="Standard_LRS"
ZIP_FILE=product-service-azure.zip
CURRENT_DATE=$(date +%Y%m%d)
SAS_EXPIRY=$(date -d "$CURRENT_DATE +10 years" +%Y-%m-%d)
# Create a resource group
az group create --location $REGION --name $RESOURCE_GROUP
# Create a storage account
az storage account create --name $STORAGE_ACCOUNT --resource-group $RESOURCE_GROUP --sku $STORAGE_SKU
# Create a function app
az functionapp create \
--name $FUNCTION_NAME \
--resource-group $RESOURCE_GROUP \
--storage-account $STORAGE_ACCOUNT \
--consumption-plan-location $REGION \
--functions-version 4 \
--os-type linux \
--runtime java \
--runtime-version 11.0
Next upload the function package and generate an SAS token:
# Upload the function package
az storage blob upload \
--account-name $STORAGE_ACCOUNT \
--container-name java-functions-run-from-packages \
--name product-service-azure.zip \
--file /tmp/octopubproductservice/product-service-azure.zip \
--overwrite \
--auth-mode key
# Create a SAS key for the function package
URL=$(az storage blob generate-sas \
--account-name $STORAGE_ACCOUNT \
--container-name java-functions-run-from-packages \
--name product-service-azure.zip \
--permissions r \
--expiry $SAS_EXPIRY \
--auth-mode key \
--full-uri)
# The URL is quoted. We treat this as a JSON string, and use jq to return the raw string
FIXED_URL=$(echo $URL | jq -r '.')
Finally, set the WEBSITE_RUN_FROM_PACKAGE setting to the SAS URL, which is required when deploying Linux functions:
# The raw string is set as the WEBSITE_RUN_FROM_PACKAGE value, which indicates Azure
# must download the function from the URL.
az functionapp config appsettings set \
--name $FUNCTION_NAME \
--resource-group $RESOURCE_GROUP \
--settings "WEBSITE_RUN_FROM_PACKAGE=$FIXED_URL"
At that point your Quarkus app should be working.

Fixing breaking changes when migrating from Azure AD to Microsoft.Graph API?

I am attempting to setup and install this reference app from Azure, created by the Microsoft patterns & practices team: https://github.com/mspnp/serverless-reference-implementation - the setup is via Azure CLI not the UI.
However it uses Azure AD Graph, which has just very recently been deprecated and replaced by Microsoft.Graph as documented here: https://learn.microsoft.com/en-gb/cli/azure/microsoft-graph-migration
This breaks the installation instructions in the app, specifically the az ad app create command:
export API_APP_ID=$(az ad app create --display-name $API_APP_NAME --oauth2-allow-implicit-flow true \
--native-app false --reply-urls http://localhost --identifier-uris "http://$API_APP_NAME" \
--app-roles ' [ { "allowedMemberTypes": [ "User" ], "description":"Access to device status", "displayName":"Get Device Status", "isEnabled":true, "value":"GetStatus" }]' \
--required-resource-accesses ' [ { "resourceAppId": "00000003-0000-0000-c000-000000000000", "resourceAccess": [ { "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", "type": "Scope" } ] }]' \
--query appId --output tsv)
Fails with: ERROR: unrecognized arguments: --native-app false
If I try to update the command with the new parameters for Microsoft.Graph as per the migration guide above:
export API_APP_ID=$(az ad app create --display-name $API_APP_NAME --enable-access-token-issuance true \
--is-fallback-public-client false --web-redirect-uris http://localhost --identifier-uris "http://$TENANT_NAME.onmicrosoft.com/$API_APP_NAME" \
--app-roles ' [ { "allowedMemberTypes": [ "User" ], "description":"Access to device status", "displayName":"Get Device Status", "isEnabled":true, "value":"GetStatus" }]' \
--required-resource-accesses ' [ { "resourceAppId": "00000003-0000-0000-c000-000000000000", "resourceAccess": [ { "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", "type": "Scope" } ] }]' \
--query appId --output tsv)
The create command works - but the app's manifest does not have the expected data:
export API_IMPERSONATION_PERMISSION=$(az ad app show --id $API_APP_ID --query "oauth2Permissions[?value == 'user_impersonation'].id" --output tsv)
This returns NULL - the new Microsoft.Graph API does not even create this field in the app's manifest. I manually confirmed this by looking at the manifest in the Azure UI. This means the following commands that rely on this field existing are unusable.
How can I fix this so I can install this reference app given that the install instructions refer to the no longer available Azure AD Graph API? What is the correct az ad app create command that lets Microsoft.Graph API create the API app with oauth?

Create data container via Azure Machine learning REST API

I understand API is in preview but maybe someone can help me out here .
I am trying to create Data container as its described in AML REST API
curl --location --request PUT 'https://management.azure.com/subscriptions/{{subscriptionId}}/resourceGroups/{{resourceGroupName}}/providers/Microsoft.MachineLearningServices/workspaces/{{workspaceName}}/data/abc?api-version=2021-03-01-preview' \
--header 'Authorization: Bearer ' \
--header 'Content-Type: application/json' \
--data-raw '{"properties": { "description": "string",
"tags": { },
"properties": {}
}
}'
I receive 400 status code with message
Error setting value to 'Description' on 'Microsoft.MachineLearning.ManagementFrontEnd.Contracts.V20210301Preview.Assets.DataContainer'."
after removing Description which should be optional
DataContainers_CreateOrUpdate is not supported
How can I create Dataset with local files? I cannot use UI. There it works and I can receive it with GET list method.
If you want to create a dataset from local file, you can use az ml cli. Use following command from a powershell:
az ml dataset create --file data.yaml --resource-group "your-resource-group" --workspace-name "your-ws-name"
data.yaml
$schema: https://azuremlschemas.azureedge.net/latest/dataset.schema.json
name: local-file-example
description: Dataset created from local file.
local_path: data/titanic.csv
See az yaml schema and az dataset cli.
It seems like API version 2021-03-01-preview is not working properly for dataset operations. By reverse-engineering the az CLI command mentioned by qiax using the --debug option I could see that the endpoint used by the CLI is the following:
https://management.azure.com/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.MachineLearningServices/workspaces/{workspace}/datasets/{dataset-name}/versions/1/?api-version=2021-10-01
Here's an example of a valid request body for that endpoint (it seems like it's the same as the Create Or Update Data Version endpoint shown in the documentation):
{
"properties": {
"isAnonymous": false,
"paths": [
{
"file": "foo/"
}
],
"properties": {},
"tags": {}
}

Can we integrate a vnet to an azure container registry by passing the vnet id in the ARM template?

"networkRuleSet":{
"defaultAction": "[if(equals(parameters('networkRuleSetStatus'), 'Enabled'), 'Deny', 'Allow')]",
"virtualNetworkRules":[{
"action": "Allow",
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('existingVnetName'), parameters('existingSubnetName'))]"
}],
"copy":[{
"name":"ipRules",
"count":"[length(parameters('ip'))]",
"input":{
"action": "Allow",
"value": "[parameters('ip') [copyIndex('ipRules')]]"
}
}]
},
The above lines are part of the ARM to pass the vnetid in the network section.
It's possible to integrate a vnet to the Azure container registry and what you did is right. But there is one thing you may miss. The thing is when you want to allow a subnet to access the container registry, you need to enable the private endpoint for the container registry in that subnet. The example CLI command here:
az network vnet subnet update \
--name myDockerVMSubnet \
--vnet-name myDockerVMVNET \
--resource-group myResourceGroup \
--service-endpoints Microsoft.ContainerRegistry
After this action, then you can add the network rule through the template as you showed.

Resources