Arm Template (Bicep): Circular Dependency when merging appsettings (list function) - azure

I'm trying to update the AppSettings of an App Service through a bicep file.
When doing this in my bicep template:
var currentAppSettings = list('Microsoft.Web/sites/appServiceName/config/appsettings', '2018-11-01')
var newAppSettings = {
test: 'testValue'
}
var mergedAppSettings = union(currentAppSettings, newAppSettings)
resource appServiceConfig 'Microsoft.Web/sites/config#2018-11-01' = {
name: 'appServiceName/appSettings'
properties: mergedAppSettings
}
...I get a circular dependency error when deploying the bicep file:
"Deployment template validation failed: 'Circular dependency detected on resource: '/subscriptions/293d7347-b26f-4413-9986-d61717aaff26/resourceGroups/WSAPlayground/providers/Microsoft.Web/sites/playground-fitxp-backend-euw-wa/config/appSettings'. Please see https://aka.ms/arm-template/#resources for usage details.'."
Is there a way to do this without getting the dependency error?

try using modules. Bicep modules are essentially nested deployments. in the top level file (i. e. main) extract the current values and pass them to the submodule (appsettings) as parameter of type object and then execute merge and update.
clue is to deploy the update in a different module than reading current value.

Using modules doesn't seem to help if the deployment both creates the app service / function app and sets the app settings. This causes a circular dependency error.
Instead, the solution I have ended up using is to move the extraction of the current app settings outside of the bicep template, and pass them in as a parameter. Something like this bash script:
existingAppSettings="{}"
functionAppAlreadyDeployed=$(az appservice plan list --query "[?name=='ic-portfolio-service-preprod-app-plan']" | jq length)
if [functionAppAlreadyDeployed -eq 1]
then
existingAppSettings=$(az functionapp config appsettings list --name ic-${{parameters.serviceName}}-${{parameters.environment}} --resource-group ${{parameters.serviceName}}-${{parameters.environment}} | jq -r 'map( { (.name): .value } ) | add')
fi
az deployment group create \
--name "deploymentNameGoesHere" \
--resource-group "resourceGroupNameGoesHere" \
--template-file "$(Pipeline.Workspace)/templatepathgoeshere/main.bicep" \
--parameters "buildNumber=$(Build.BuildNumber)" \
"existingAppSettings=$existingAppSettings" \
--mode Complete
NB - I am using az appservice plan list because appservice doesn't support exists
You can then pass this into the bicep template as an object:
#secure()
param existingAppSettings object
And use as follows:
var appSettings = {
New app settings go here
}
resource functionAppAppsettings 'Microsoft.Web/sites/config#2018-11-01' = {
name: '${functionAppName}/appsettings'
properties: union(existingAppSettings, appSettings)
}

Related

Bicep Template ~ Create directories in ADLS

I'm trying to transition from Terraform with the azurerm provider to Bicep and having a tohgh time figuring out how to use Bicep to populate my required ADLS Gen 2 directory structure.
Many of my builds need a new ADLS with lots of containers, then inside each container I need nested directories, sometimes three or four levels deep. In Terraform this is pretty simple using the storage/path resource type: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_data_lake_gen2_path
I cannot see any equivalent using Bicep. What am I missing?
The only possibility that seems remotely feasible to accomplish this is to package a deployment Powershell or CLI script, but that looks like a lot of extra configuration and effort for something this trivial.
I would provide code samples for my bicep, but they would only show the storage and container resources and probably would not be very useful. The container resource works perfectly for creating the root directories - but I cannot see how to get Bicep to create directories/paths within them. Can anyone assist, please?
Update
Does not appear to be possible in Bicep. Happy to be proven wrong.
You will have to work with a deployment script to create directories in ADLS Gen2 file systems. You can include inline Azure CLI scripts in Bicep templates. You can create the directory using the Azure CLI command az storage fs directory create. If we include this command in a Bicep template deploying a ADLS Gen 2 storage account, it would look like this:
param location string = 'westeurope'
param containerName string = 'mycontainer'
param directoryName string = 'mydirectory'
resource storageAccount 'Microsoft.Storage/storageAccounts#2022-09-01' = {
name: uniqueString(resourceGroup().id)
kind: 'StorageV2'
location: location
sku: {
name: 'Standard_LRS'
}
properties: {
isHnsEnabled: true
}
resource container 'blobServices#2022-09-01' = {
name: 'default'
resource container 'containers#2022-09-01' = {
name: containerName
}
}
}
resource createDirectory 'Microsoft.Resources/deploymentScripts#2020-10-01' = {
name: 'createDirectory'
kind: 'AzureCLI'
location: location
properties:{
azCliVersion: '2.42.0'
retentionInterval: 'P1D'
arguments: '\'${storageAccount.name}\' \'${containerName}\' \'${directoryName}\''
scriptContent: 'az storage fs directory create --account-name $1 -f $2 -n $3 --auth-mode key'
environmentVariables: [
{
name: 'AZURE_STORAGE_KEY'
secureValue: storageAccount.listKeys().keys[0].value
}
]
}
}

publishing azure function - can you create a template json resource file

I have an Azure function that needs an automated deployment script. We currently have a line in the Powershell script that looks like this:
#create resources defined in JSON -
az deployment group create --resource-group TESTGROUP --template-file resources.json
This is what the resource file has for the function name:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"functionapp_name": {
"defaultValue": "[concat('widgets-',uniqueString(resourceGroup().id))]",
"type": "String"
}
This code works fine but I don't want to use dynamic function names anymore. What I'm trying to accomplish is the following:
if local.settings.json exists, then I want to call the function name by the developer's machine hostname
if there is no local.settings.json file then i know this is for a prod env so I want to use different value.
Is there a simple way to do this?
Try this :
$file = 'path\to\local.settings.json'
$functionAppName = 'nameToGiveYourFunctionAppIfInProd'
#If the file exists, use dev machine hostname.
if (Test-Path -Path $file -PathType Leaf) {
$functionAppName = [System.NET.DNS]::GetHostByName('').HostName
}
#Now run your az deployment script and pass the funcAppName as parameter
#create resources defined in JSON -
az deployment group create --resource-group TESTGROUP --template-file resources.json --parameters functionapp_name=$functionAppName

How to use variables in Azure CLI step in Azure CI/CD

I'm trying to deploy my configuration settings using Azure CLI step in my release pipeline.
There are multiple commands in it that I need to run which looks like this.
- *az webapp config settings set -g resourceGroupName -n WebAppName
--settings somekey=somevalue*
Note that There is a resourcegroupname and webappname that are present in it.
How Can I create a Variable for those two values and use them in my CLI.
I have tried adding them to the arguments but it didn't work.
Getting below error
validation error: Parameter 'resource_group_name' must conform to the following pattern: '^[-\\w\\._\\(\\)]+[^\\.]$'.
The reason being that I have 30 odd values and I need to create those variables for webapp which is present in multiple resource groups, So that I can simply swap the name of resource group and run the CLI.
You need to define variable in your pipeline and then use them in Azure Cli step.
So if you have variable named ResourceGroup you should have
az webapp config settings set -g $(ResourceGroup) -n WebAppName --settings somekey=somevalue
You can also create variable group and reuse it across your pipelines.

Azure Function App - How to obtain the Invoke Url and code

I've created and successfully tested a Function App that requires the .net Framework because of a legacy library, and is set to use run-time version ~1. I'm looking for the Invoke Url and code, to help automate deployment.
Following this MS article and using the azure-functions-core-tools v2 (npm i -g azure-functions-core-tools#^2), I can see the Invoke Url when publish is called with the --verbose option.
However, because of the .net Framework requirement and run-time version ~1, we're bound to azure-functions-core-tools v1 (npm i -g azure-functions-core-tools#^1) (see here). Executing any of the commands from func azure functionapp does’t include the Invoke Url. The --verbose option is not available.
>func azure functionapp publish <MyApp>
Getting site publishing info...
Publish C:\<MyProject> contents to an Azure Function App. Locally deleted files are not removed from destination.
Creating archive for current directory...
Uploading archive...
Upload completed successfully.
Same for list-functions
>func azure functionapp list-functions <MyApp>
Functions in <MyApp>:
FunctionOne - [httpTrigger]
FunctionTwo - [httpTrigger]
I haven't tried ARM yet.
Is there a way to obtain the Invoke Url for Function Apps on run-time version ~1?
I get the Invoke Url and the code with the following Azure CLI commands:
FUNCTION_CODE=$(az functionapp function keys list -g ${SOLUTION_NAME} -n $FUNCTIONS_NAME --function-name DPSCustomAllocationFunction --query "default")
FUNCTION_CODE=$(echo "$FUNCTION_CODE" | tr -d '"') #Remove "" from result
FUNCTION_URL=$(az functionapp function show --function-name DPSCustomAllocationFunction --resource-group $SOLUTION_NAME --query "invokeUrlTemplate" --output tsv --name $FUNCTIONS_NAME)
FUNCTION_URL=$(echo $FUNCTION_URL|tr -d '\r\n') #Remove breaklines from result
INVOKE_FUNCTION="$FUNCTION_URL?code=$FUNCTION_CODE"
Yo could use the REST API to get it:List Function Secrets, it will response the secret and triggerUrl.
POST https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/functions/{functionName}/listsecrets?api-version=2016-08-01
Also you could implement it with the PowerShell GetFunctionInvokeUrl to do it.
You can do this with Azure CLI:
az functionapp function show
az functionapp function show --function-name MyFunction --name MyApp --resource-group MyResourceGroup --query "invokeUrlTemplate" --output tsv

Azure function app create

I´m using az functionapp create for creating function ap in Azure, where apparts of creating the function app it also hooks it to a bitbucket repo. I´m using parametere --deployment-source-url -u but it seems is not working this way and is giving me an error. This is done by a jenkin file pipeline
node {
stage('Azure Login') {
withCredentials([azureServicePrincipal('6-8afd-ae40e9cf1e74')]) {
sh 'az login --service-principal -u $AZURE_CLIENT_ID -p $AZURE_CLIENT_SECRET -t $AZURE_TENANT_ID'
sh 'az account set -s $AZURE_SUBSCRIPTION_ID'
}
}
stage('Build Azure FuntionApp') {
sh 'az functionapp create -g $RG_NAME -p $SP_NAME -n grey-$JOB_NAME-$BUILD_NUMBER -s $SA_NAME --deployment-source-url https:// bitbucket.org/xxxx/functions/s***strong text***rc/develop --debug'
}
If I put --deployment-source-url -u https://user#bitbucket.org I get:
ERROR: az functionapp create: error: argument
--deployment-source-url/-u: expected one argument
I tried without the -u just : --deployment-source-url https://#bitbucket.org
and the job gets done, but the link with bitbucket repos is not made. Getting this:
So how is it that this work? how come if I put user it says invalid argument and if I don´t it pases but It can find user. Does anyone ever used this command to create a function app? thanks!
If you want to create azure function via azure-cli, you could change the deployment resource url after --deployment-source-url. You could refer to my command to create a function with a blob trigger, replace the url of yours. It works fine on my side.
Note: The Access level should be public, you could check it in Settings like the screenshot below.
az functionapp create --deployment-source-url https://bitbucket.org/xxx/azure-function --resource-group resourcegroupname --consumption-plan-location westeurope --name joyfun22 --storage-account <storage_name>
Besides, you also can use a github repository to create a function.
For example, to use the command below to create a function with a blob trigger.
az functionapp create --deployment-source-url https://github.com/Joyw1/Azure-Function-Trigger --resource-group myResourceGroup --consumption-plan-location westeurope --name <app_name> --storage-account <storage_name>
Update:
If your Access level is private. You need a access token to access your bitbucket repository. Please follow the steps bellow.
1.Go to the Bitbucket Labs -> Access Management -> OAuth -> Add consumer
More details, refer to this link.
2.Enable authenticated git deployment with Azure CLI
#!/bin/bash
gitrepo=<Replace with your GitHub repo URL e.g. https://github.com/Azure-Samples/functions-quickstart.git>
token=<Replace with a GitHub access token>
# Enable authenticated git deployment
az functionapp deployment source update-token \
--git-token $token
For complete command, refer to this link.

Resources