Highlight
Here’s how you can deploy Azure Logic Apps standard in a quick and easy way with Azure DevOps.
Logic Apps Standard might be quite tricky to deploy continously at first. But in this article I’ll share my personal CICD templates which can help speed up this process, with extra powershell scripts to make this more end-2-end in terms of functionality.
DevOps setup
Pre-requisites
- Set up Azure ARM connection for your project with permissions to deploy code into designated subscription/rg/logic app
- Permissions to set up new pipelines in Azure DevOps
- Permissions to set up new variable groups in Azure DevOps
Folder Structure
Azure DevOps repo should have following structure
FOLDER STRUCTURE NOTES
<root>
├───🗂️ code folder for logic app code
│ ├──📄 ...
│ └──📄 ...
└───🗂️ pipelines folder for devops pipelines
├───🗂️ scripts extra powershell scripts called from pipeline
│ ├──📄 ...
│ └──📄 update-la-settings.ps1 update logic app standard settings
└──📄 la-cicd-pipeline.yml deployment pipeline
Variable Group
Create a variable group of any name, recommendation is to use one variable group per environment (DEV/TEST/PROD).
- SubscriptionId - Subscription ID where logic app is residing
- ResourceGroupName - Resource Group ID where logic app is residing
- LogicAppName - Name of Logic App standard resource
- EnableWorkflowList - list of workflow names to enable forcefully after deployment, even if they are disabled on DEV
- use @() for empty list
- or “A”, “B”, “C” notation for powershell lists
- DisableWorkflowList - list of workflow names to disable forcefully after deployment, even if they are enabled on DEV
- use @() for empty list
- or “A”, “B”, “C” notation for powershell lists
- AppSettingOverrideList - list of app service settings to override after code deployment
- use @() for empty list
- or “A=123”, “B=432”, “C=ZYX” notation for powershell lists of setting paris in format of “setting_name=setting_value”
Flow
In order to deploy Logic App we will follow two step process
-
Build stage where we get current code, override variables that change between environments in static files, and zip it
-
Publish ZIP package to Azure and override app service settings
Build & Deploy pipeline
Here’s the final YAML pipeline script for easy copy and paste
└───🗂️ pipelines
└──📄 la-cicd-pipeline.yml
With following source
name: LogicAppCICD_$(Date:yyyyMMdd)$(Rev:.r)
trigger: none
pool:
vmImage: ubuntu-latest
variables:
- group: <variable_group_name>
- name: connectionName
value: <azure_arm_connection_name>
- name: logicAppPackageName
value: logic-app-pkg.zip
stages:
- stage: Build
displayName: Build Package
jobs:
- job: BuildAndPublishPackage
displayName: Build & Publish Package
steps:
- task: PublishPipelineArtifact@1
inputs:
targetPath: $(Build.SourcesDirectory)/code
artifact: LogicAppCode
- task: ArchiveFiles@2
inputs:
rootFolderOrFile: $(Build.SourcesDirectory)/code
includeRootFolder: false
archiveType: zip
archiveFile: $(System.DefaultWorkingDirectory)/$(logicAppPackageName)
- task: PowerShell@2
displayName: Connections JSON exists
inputs:
targetType: 'inline'
script: |
$fileExists = Test-Path -Path "$(Build.SourcesDirectory)/code/connections.json"
Write-Output "##vso[task.setvariable variable=FileExists]$fileExists"
- task: FileTransform@1
displayName: Connections JSON transform
condition: eq(variables['FileExists'], True)
inputs:
folderPath: $(System.DefaultWorkingDirectory)/$(logicAppPackageName)
fileType: json
targetFiles: '**/connections.json'
- task: PowerShell@2
displayName: Parameters JSON exists
inputs:
targetType: 'inline'
script: |
$fileExists = Test-Path -Path "$(Build.SourcesDirectory)/code/parameters.json"
Write-Output "##vso[task.setvariable variable=FileExists]$fileExists"
- task: FileTransform@1
displayName: Parameters JSON transform
condition: eq(variables['FileExists'], True)
inputs:
folderPath: $(System.DefaultWorkingDirectory)/$(logicAppPackageName)
fileType: json
targetFiles: '**/parameters.json'
- task: PublishPipelineArtifact@1
inputs:
targetPath: $(System.DefaultWorkingDirectory)/$(logicAppPackageName)
artifact: LogicAppCodePackage
- stage: Deploy
displayName: Deploy
jobs:
- job: Deploy
displayName: Deploy
steps:
- task: DownloadPipelineArtifact@2
inputs:
buildType: 'current'
targetPath: $(System.DefaultWorkingDirectory)
artifact: LogicAppCodePackage
- script: ls $(System.DefaultWorkingDirectory)
displayName: Working Directory
- task: AzurePowerShell@5
displayName: Overriding LA Settings
inputs:
azureSubscription: ${{ variables.connectionName }}
scriptType: filePath
scriptPath: $(Build.SourcesDirectory)/pipelines/scripts/update-la-settings.ps1
scriptArguments:
-SubscriptionId $(SubscriptionId)
-ResourceGroupName $(resourceGroupName) `
-LogicAppName $(logicAppName) `
-EnableWorkflowList $(enableWorkflowList) `
-DisableWorkflowList $(disableWorkflowList) `
-AppSettingOverrideList `
"MessageFromAppSetting=PROD!"
azurePowerShellVersion: latestVersion
pwsh: true
- task: AzureFunctionApp@2
displayName: 'Deploy logic app workflows'
inputs:
azureSubscription: ${{ variables.connectionName }}
appType: functionApp
appName: $(logicAppName)
package: $(System.DefaultWorkingDirectory)/$(logicAppPackageName)
Updating Azure App Service settings
Why? Azure App Service holds two things that are important from the perspective of Azure Logic Apps.
- Connector Connection Strings
- Logic App Workflow state
Attached script allows you to do a bulk update of these properties as part of the workflow. This allows you to solve two scenarios
- Update connection strings when promoting code between DEV, TEST, PROD environments
- Disable workflows which you don’t want to run after deployment, this is especially important when deploying app with triggers
How? - update-la-settings.ps1
For this I’ve created a small PowerShell script which will be invoked from DevOps pipeline
└───🗂️ pipelines
└───🗂️ scripts
└──📄 update-la-settings.ps1
With following code
param(
[Parameter(Mandatory=$true)]
[string]
$SubscriptionId,
[Parameter(Mandatory=$true)]
[string]
$ResourceGroupName,
[Parameter(Mandatory=$false)]
[string]
$LogicAppName,
[Parameter(Mandatory=$false)]
[string[]]
$EnableWorkflowList,
[Parameter(Mandatory=$false)]
[string[]]
$DisableWorkflowList,
[Parameter(Mandatory=$false)]
[string[]]
$AppSettingOverrideList
)
$webApp = Get-AzWebApp `
-Name $LogicAppName `
-ResourceGroupName $ResourceGroupName
$currentSettings = $webApp.SiteConfig.AppSettings
$NewAppSettings = @{}
foreach ($setting in $currentSettings) {
$NewAppSettings[$setting.Name] = $setting.Value
}
foreach ($WorkflowName in $EnableWorkflowList) {
Write-Output "Setting: Workflows.$WorkflowName.FlowState = Enabled"
$NewAppSettings["Workflows.$WorkflowName.FlowState"] = 'Enabled'
}
foreach ($WorkflowName in $DisableWorkflowList) {
Write-Output "Setting: Workflows.$WorkflowName.FlowState = Disabled"
$NewAppSettings["Workflows.$WorkflowName.FlowState"] = 'Disabled'
}
foreach ($Setting in $AppSettingOverrideList) {
$name = $Setting.split("=")[0]
$value = $Setting.split("=")[1]
Write-Output "Setting: $name = $($value.substring(0, [System.Math]::Min(10, $value.Length)))..."
$NewAppSettings[$name] = $value
}
Set-AzWebApp `
-AppSettings $NewAppSettings `
-Name $LogicAppName `
-ResourceGroupName $ResourceGroupName
How it works? You simply need to provide 6 parameters, all are mandatory
- SubscriptionId - Subscription ID where logic app is residing
- ResourceGroupName - Resource Group ID where logic app is residing
- LogicAppName - Name of Logic App standard resource
- EnableWorkflowList - list of workflow names to enable forcefully after deployment, even if they are disabled on DEV
- use @() for empty list
- or “A”, “B”, “C” notation for powershell lists
- DisableWorkflowList - list of workflow names to disable forcefully after deployment, even if they are enabled on DEV
- use @() for empty list
- or “A”, “B”, “C” notation for powershell lists
- AppSettingOverrideList - list of app service settings to override after code deployment
- use @() for empty list
- or “A=123”, “B=432”, “C=ZYX” notation for powershell lists of setting paris in format of “setting_name=setting_value”
Example usage in devops step
- task: AzurePowerShell@5
displayName: Overriding LA Settings
inputs:
azureSubscription: ${{ variables.connectionName }}
scriptType: filePath
scriptPath: $(Build.SourcesDirectory)/pipelines/scripts/update-la-settings.ps1
scriptArguments:
-SubscriptionId $(SubscriptionId)
-ResourceGroupName $(resourceGroupName) `
-LogicAppName $(logicAppName) `
-EnableWorkflowList $(enableWorkflowList) `
-DisableWorkflowList $(disableWorkflowList) `
-AppSettingOverrideList `
"<setting_name>=<setting_value>"
azurePowerShellVersion: latestVersion
pwsh: true
And simply run
If you did everything right, you should see deployment succeed.