How can I deploy a prepackaged Quarkus Azure Functions app - azure

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.

Related

Unable to remove URL from Azure App Registrations

I'm trying to remove a specific URL from Azure App Registrations. I tried the below command.
az ad app update --id <app-id> --remove web-redirect-uris 0
I used '0' (Index) as it doesn't allow us to delete the URL value. But it gives below error.
Couldn't find 'web' in 'web.redirect'. Available options: []
UPDATED
az rest \
--method PATCH \
--uri "https://graph.microsoft.com/v1.0/applications/<object-id>" \
--headers 'Content-Type=application/json' \
--body “{web:{redirectUris: https://URL1}}”
unrecognized arguments: https://URL1}}”
New
az rest \
--method "delete" \
--uri "https://graph.microsoft.com/v1.0/applications/<object-id>" \
--headers "{'Content-Type': 'application/json'}" \
--body "{'web': 'redirectUris': [ 'https://URL1' ] }"
As per august 2022, it is not supported anymore (due to MS Graph Migration).
From the documentation:
Generic update arguments --add, --set and --remove currently don't work. You may use az rest to directly call Microsoft Graph API for non-supported properties.
You can track the github issue here: Azure CLI cannot set values on nested properties.
so in your case something like that should work
az rest \
--method "patch" \
--uri "https://graph.microsoft.com/v1.0/applications/<object-id>" \
--headers "{'Content-Type': 'application/json'}" \
--body "{'web': 'redirectUris': [ 'https://URL1' ] }"

Use external parameters.json file not working with Azure CLI

I am trying to pass parameters in via the parameter file in Azure Cli
The script below ignores my file
What am I doing wrong?
I have also tried ParameterTemplateFile as mentioned in another post here but that doesnt work either
templateFile="Path\template.json"
parameterFile="Path\parameters.json"
az deployment group create \
--name <NAME> \
--resource-group <RESOURCE GROUP>\
--template-file $templateFile \
--parameter-file $parameterFile
When running via Azure Cli I should have been using #parameters.json

How do I know which image version is installed on a specific instance of an Azure VMSS?

I have an Azure VMSS (Virtual Machine Scale Set) with a few instances, linked to an "image gallery". The VMSS is configured in such a way that it is supposed to always choose the latest version of a specific image from the image gallery.
How and where can I see, which version of the image is installed on a specific instance?
If the image gallery is configured to install the latest image on new instances, the image version can potentially vary between instances. The actually installed version of an image is stored in the storageProfile.imageReference.exactVersion property of the vmss object.
Listing the installed image version for a specific machine in an existing scale set:
az vmss show --resource-group "<resource group name>" \
--subscription "<subscription name>" \
--name <vmss name> \
--instance-id <instance id> \
--query storageProfile.imageReference.exactVersion
The reply matches the version number defined in the image gallery:
"2021.06.1782103"
If the instance id is not known, it is possible to get all instance ids of an existing scale set:
az vmss list-instances --resource-group "<resource group name>" \
--subscription "<subscription name>" \
--name <vmss name> \
--query [].instanceId
[
"1141",
"1142",
"1143"
]
To further simplify things, one could list the installed image version for each machine in an existing scale set. This allows, for example, to see if all instances are at the same version or one is left behind:
az vmss list-instances --resource-group "<resource group name>" \
--subscription "<subscription name>" \
--name <vmss name> \
--query [].storageProfile.imageReference.exactVersion
In an example with 3 instances the reply may indicate that two machines are on the later version (...03), and one machine is still on an older version of the image (...02):
[
"2021.06.1782102",
"2021.06.1782103",
"2021.06.1782103"
]
Finally, to combine this one can also query for instanceId and installed image version at the same time:
az vmss list-instances --resource-group "<resource group name>" --subscription "<subscription name>" --name <vmss name> --query "[].[instanceId,storageProfile.imageReference.exactVersion]"
[
[
"1141",
"2021.06.1782102"
],
[
"1142",
"2021.06.1782103"
],
[
"1143",
"2021.06.1782103"
]
]
You can get the exect version of image reference for one specfic instance by using the Get-AzVmssVM cmdlet with the following sytax:
(Get-AzVmssVM -ResourceGroupName $rgName -Name $ScaleSetName -InstanceId $instanceId).StorageProfile.ImageReference

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

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"

Creating application insights with azure cli

I would like to create application insights using AZURE CLI. I can't find any documentation on this topic. Is it possible?
The link provided by Rohit works
az resource create \
--resource-group $RESOURCE_GROUP \
--resource-type "Microsoft.Insights/components" \
--name $NAMESPACE_PREFIX-appinsights \
--location $PRIMARY_LOCATION \
--properties '{"Application_Type":"web"}'
https://github.com/Azure/azure-cli/issues/5543#issuecomment-365001620
The az monitor app-insights component provide commands for creating, inspecting modifying, and deleting application insights components from the command line.
Use: az monitor app-insights component create
az monitor app-insights component create --app
--location
--resource-group
[--application-type]
[--ingestion-access {Disabled, Enabled}]
[--kind]
[--query-access {Disabled, Enabled}]
[--retention-time]
[--tags]
[--workspace]
If you need to associate the generated instrumentation key with another resource, such as a function app, you can use grep and xargs as follows:
# Creates insights component for monitoring. Note generated instrumentation key
# is set in function app.
az resource create \
--resource-group ${RESOURCE_GROUP_NAME} \
--resource-type "Microsoft.Insights/components" \
--name ${FUNCTION_APP_NAME} \
--location ${LOCATION} \
--properties '{"Application_Type":"web"}' \
| grep -Po "\"InstrumentationKey\": \K\".*\"" \
| xargs -I % az functionapp config appsettings set \
--name ${FUNCTION_APP_NAME} \
--resource-group ${RESOURCE_GROUP_NAME} \
--settings "APPINSIGHTS_INSTRUMENTATIONKEY = %"
Application Insights is an extensible Application Performance Management (APM) service for web developers on multiple platforms. You can use it to monitor your live web application. You can get more details about Application Insights.
It belongs to the Azure Monitor. You can find appropriate CLI command from az monitor. Hope this will be helpful.

Resources