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
Related
I'm trying to create an Azure Resource Group using a .bicep file:
targetScope = 'subscription'
param environment string
param location string = deployment().location
resource resourceGroup 'Microsoft.Resources/resourceGroups#2021-04-01' = {
name: 'snapshot-generator-${environment}-west-eu'
location: location
}
And for deploy I'm using the following command in PowerShell:
New-AzResourceGroupDeployment -TemplateFile resourceGroup.bicep
but the ResourceGroupName is requested and I can't understand why and what I'm doing wrong.
You should use New-AzSubscriptionDeployment instead of New-AzResourceGroupDeployment for a subscription-level deployment. See here for more.
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)
}
Issue: error on ADF when trying to create ADF Components such as dataset for AzureSQLMITable via powershell
Analysis:
Error is reproducable on BuildServer (run via DevOps) & locally via Windows PowerShell.
Error is not reproducible in Azure Cloudshell & Powershell core with same set of commands
Error on ADF for the dataset:
Could not load resource #datasetname. Please ensure no mistakes in the JSON and that referenced resources exist. Status: UnknownError, Possible reason: Fetch failed for named: dataset$#datasetname. Adapter not found. Type: dataset.
If manually pasted the file(jsonfile) in ADF it works as expected without error
Expected resolution: How to make it work with WindowsPowershell?
Json file:
{
"name": "#datasetname",
"properties": {
"linkedServiceName": {
"referenceName": "<connection name>",
"type": "LinkedServiceReference"
},
"annotations": [],
"type": "AzureSqlMITable",
"schema": [],
"typeProperties": {
"tableName": {
"value": "<StoredProcedure_Name_Name>",
"type": "Expression"
}
}
},
"type": "Microsoft.DataFactory/factories/datasets"
}
Powershell commands:
Connect-AzureRmAccount
$BaseFolder=<FilePath>
$file = Get-ChildItem $BaseFolder -Recurse -Include *.json -Filter #somefilter -ErrorAction Stop
Set-AzureRmDataFactoryV2Dataset -DataFactoryName <datafactoryname> -Name ($file.BaseName) -ResourceGroupName <resourcegroupname> -DefinitionFile $file.FullName -Force -ErrorAction Stop
Resolved with Az Commands using powershell core commands(via Azure Powershell task in CICD instead of Powershell script which was Windows one).
The point here is that henceforth people should use Powershell core(Az) as it will have new feature and windows powershell(AzureRm) will only have bug fixes
My Azure Service Fabric application sometimes requires paths longer than MAX_PATH, especially given the length of the work directory. As such, I'd like to enable long file paths (via the registry's LongPathsEnabled value, via group policy, or via some other mechanism, see https://superuser.com/questions/1119883/windows-10-enable-ntfs-long-paths-policy-option-missing). But I can't figure out how to do that.
The cluster runs on an Azure VMSS, so I can remote into the individual instances and set it manually, but that doesn't scale well of course.
UPDATE:
#4c74356b41's answer got me most of where I needed to be. My VMSS already had a customScript extension installed, so I actually had to modify it to include the PS command, here's my final command:
# Get the existing VMSS configuration
$vmss = Get-AzVmss -ResourceGroupName <resourceGroup> -Name <vmss>
# inspect $vmss to determine which extension is the customScript, in ours it's at index 3. Note the existing commandToExecute blob, you'll need to modify it to add the additional PS command
# modify the existing Settings.commandToExecute blob to add the reg set command
$vmss.VirtualMachineProfile.ExtensionProfile.Extensions[3].Settings.commandToExecute = 'powershell -ExecutionPolicy Unrestricted -File AzureQualysCloudAgentPowerShell_v2.ps1 && powershell -c "Set-ItemProperty -Path HKLM:\System\ControlSet001\Control\FileSystem -Name LongPathsEnabled -Value 1"'
# update the VMSS with the new config
Update-AzVmss -ResourceGroupName $vmss.ResourceGroupName -Name $vmss.Name -VirtualMachineScaleSet $vmss
I'd suggest using script extension and a simple powershell script to set this value. this will automatically get applied to all the instances (including to when you scale).
{
"apiVersion": "2018-06-01",
"type": "Microsoft.Compute/virtualMachineScaleSet/extensions",
"name": "config-app",
"location": "[resourceGroup().location]",
"properties": {
"publisher": "Microsoft.Compute",
"type": "CustomScriptExtension",
"typeHandlerVersion": "1.9",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": []
},
"protectedSettings": {
"commandToExecute": "powershell -c 'Set-Item HKLM:\System\CurrentControlSet\Policies\LongPathsEnabled -Value 1'"
}
}
}
The command itself is probably a bit off, but you can experiment on your local and get it right and then put it into the script extension
https://learn.microsoft.com/en-us/azure/virtual-machines/extensions/custom-script-windows
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"