Pingpong
Pingpong

Reputation: 8009

Logic Apps workflows via Terraform and Azure

We have Terraform to create and deploy Logic Apps.

We also have created workflows in Logic Apps.

We want to automate the creations of both Logic Apps and workflows within it.

For example please see the workflows below:

enter image description here https://learn.microsoft.com/en-us/azure/logic-apps/tutorial-build-schedule-recurring-logic-app-workflow

Upvotes: 2

Views: 19971

Answers (4)

people care
people care

Reputation: 1

I worked on the similar workflow, i split my work into multiple 1. create resource group, 2. storage account. 3. keyvault 4. keyvault connection 5.logic app (Kv and KvConnect for retrive data, logic app can be one or more)., this still can be extended to mapping with APIM and API end points creation

Upvotes: 0

Ankit Kotnala
Ankit Kotnala

Reputation: 83

On top of the above answers you can now create API connections from terraform with

azurerm_api_connection These can then be used in the connections under parameter of workflow or body of custom action

Upvotes: 4

Sven
Sven

Reputation: 2505

You should look at Logic Apps (Standard). They provide a better development/deployment experience. You can create the Logic App Standard runtime using terraform and deploy your workflows using Azure CI/CD pipelines.

However, With Logic Apps (Standard) there are only three pricing tiers availabe: WS1, WS2 and WS3. You'll always have to pay even when your instance is idle. Logic Apps (Standard) will be hosted inside an App Service. The benefits: Your workflow code can be source controlled in git and you're able to develop/debug locally in VSCode.

So it comes down to this comparison:

Logic Apps Consumption

Pros

  • you only pay for what you use (consumption pricing model)
  • develop in VSCode locally, but no debug (imho) - VSCode just connects to Azure

Cons

  • automating deployment of workflows is currently really hard (see complex terraform scripts above)
  • provides no source control
  • your workflow defintion only lives in Azure
  • no CI/CD

Logic Apps (Standard)

Pros

  • Deployment through CI/CD pipelines is possible
  • source control by git for your workflows and connections
  • VSCode integration (develop and debug locally while using the portable workflow runtime)
  • Can be parameterized (also uses appsettings)

Cons

  • you have to run a full AppService for hosting
  • the cheapest pricing model is WS1, cost about $130 per month

Currently, we decided to run Standard model, because anything can be source-controlled an automated using CI/CD. However, we only run a small number of workflows, and costs are high. We would be better going the consumption way.

Upvotes: 3

Ansuman Bal
Ansuman Bal

Reputation: 11401

There is a limitation in terraform while deploying logic app work flows ,you can't create the api connections which are required in workflows , it can be only deployed through arm template or manually from portal and then need to be manually configured inside the workflow like bingsmap connection and outlook connection .

If you are starting to deploy logic apps from terraform then quick fix will be to refer the ARM template of a workflow after creating a workflow manually going to logic app code view, to get the idea how a custom action should be written in terraform .

OR

You can just deploy the logicapp from terraform and then use the code present in logic app code view to be deployed from terraform using azurerm_resource_group_template_deployment.

References:

Another SO thread where I have mentioned about configuring webapiconnections for logic app using ARM template

***Example provide by AZApril on how to use terraform to deploy logic app and then workflow using template deployment***


For deploying the logic app and workflow you can use something like below from terraform :

provider "azurerm" {
  features{}
}

data "azurerm_resource_group" "example" {
  name="ansumantest"
}

resource "azurerm_logic_app_workflow" "example" {
  name                = "workflow1"
  location           = data.azurerm_resource_group.example.location
  resource_group_name = data.azurerm_resource_group.example.name
}

resource "azurerm_resource_group_template_deployment" "apiconnections" {
  name                = "group-deploy"
  resource_group_name = data.azurerm_resource_group.example.name
  deployment_mode     = "Incremental"
  template_content = <<TEMPLATE
{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "connections_bingmaps_name": {
            "defaultValue": "bingmaps",
            "type": "string"
        },
        "connections_office365_name": {
            "defaultValue": "office365",
            "type": "string"
        }
    },
    "variables": {},
    "resources": [
        {
    "type": "Microsoft.Web/connections",
    "apiVersion": "2016-06-01",
    "name": "[parameters('connections_bingmaps_name')]",
    "location": "eastus",
    "kind": "V1",
    "properties": {
        "displayName": "BingMapsConnection",
        "statuses": [
            {
                "status": "Connected"
            }
        ],
        "customParameterValues": {},
        "nonSecretParameterValues": {},
        "createdTime": "2022-01-24T08:26:56.8147674Z",
        "changedTime": "2022-01-24T08:28:05.4634315Z",
        "api": {
            "name": "[parameters('connections_bingmaps_name')]",
            "displayName": "Bing Maps",
            "description": "Bing Maps",
            "iconUri": "[concat('https://connectoricons-prod.azureedge.net/releases/v1.0.1538/1.0.1538.2619/', parameters('connections_bingmaps_name'), '/icon.png')]",
            "brandColor": "#008372",
            "id": "[concat('/subscriptions/<subscriptionId>/providers/Microsoft.Web/locations/eastus/managedApis/', parameters('connections_bingmaps_name'))]",
            "type": "Microsoft.Web/locations/managedApis"
        },
        "testLinks": []
    }
},
{
    "type": "Microsoft.Web/connections",
    "apiVersion": "2016-06-01",
    "name": "[parameters('connections_office365_name')]",
    "location": "eastus",
    "kind": "V1",
    "properties": {
        "displayName": "<emailid>",
        "statuses": [
            {
                "status": "Connected"
            }
        ],
        "customParameterValues": {},
        "nonSecretParameterValues": {},
        "createdTime": "2022-01-24T08:33:55.8159813Z",
        "changedTime": "2022-01-24T08:35:04.9083183Z",
        "api": {
            "name": "[parameters('connections_office365_name')]",
            "displayName": "Office 365 Outlook",
            "description": "Microsoft Office 365 is a cloud-based service that is designed to help meet your organization's needs for robust security, reliability, and user productivity.",
            "iconUri": "[concat('https://connectoricons-prod.azureedge.net/releases/v1.0.1538/1.0.1538.2621/', parameters('connections_office365_name'), '/icon.png')]",
            "brandColor": "#0078D4",
            "id": "[concat('/subscriptions/<subscriptionId>/providers/Microsoft.Web/locations/eastus/managedApis/', parameters('connections_office365_name'))]",
            "type": "Microsoft.Web/locations/managedApis"
        },
        "testLinks": [
            {
                "requestUri": "[concat('https://management.azure.com:443/subscriptions/<subscriptionId>/resourceGroups/ansumantest/providers/Microsoft.Web/connections/', parameters('connections_office365_name'), '/extensions/proxy/testconnection?api-version=2016-06-01')]",
                "method": "get"
            }
        ]
    }
}
    ],
    "outputs": {
        "bingmapid":{
            "type": "string",
            "value" : "[resourceId('Microsoft.Web/connections', parameters('connections_bingmaps_name'))]"
        } ,
        "officeid": {
            "type": "string",
            "value": "[resourceId('Microsoft.Web/connections', parameters('connections_office365_name'))]"
        }
    }
}
TEMPLATE
depends_on = [
  azurerm_logic_app_workflow.example
]
}
locals {
  bingmapconnectionid = jsondecode(azurerm_resource_group_template_deployment.apiconnections.output_content).bingmapid.value
  office365connectionid = jsondecode(azurerm_resource_group_template_deployment.apiconnections.output_content).officeid.value
}
resource "azurerm_logic_app_trigger_recurrence" "trigger" {
  name         = "Recurrence"
  logic_app_id = azurerm_logic_app_workflow.example.id
  frequency    = "Week"
  interval     = 1
  schedule {
    at_these_minutes=[0,15,30,45]
    at_these_hours =["8","9","7"]
    on_these_days=["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]
  }
  depends_on = [
    azurerm_resource_group_template_deployment.apiconnections
  ]
}

resource "azurerm_logic_app_action_custom" "action1" {
  name         = "Get_route_and_travel_time_with_traffic"
  logic_app_id = azurerm_logic_app_workflow.example.id

  body = <<BODY
{
                            "runAfter": {},
                            "type": "ApiConnection",
                            "inputs": {
                                "host": {
                                    "connection": {
                                        "name": "${local.bingmapconnectionid}"
                                    }
                                },
                                "method": "get",
                                "path": "/V3/REST/V1/Routes/@{encodeURIComponent('Driving')}",
                                "queries": {
                                    "distanceUnit": "Mile",
                                    "optimize": "timeWithTraffic",
                                    "wp.0": "21930 SE 51st ,Issaugh,WA,98029",
                                    "wp.1": "3003 160th Ave,Bellevue,WA,98029"
                                }
                            }
                        }
BODY
depends_on = [
  azurerm_logic_app_trigger_recurrence.trigger
]
}
resource "azurerm_logic_app_action_custom" "action2" {
  name         = "Create_variable_to_store_travel_time"
  logic_app_id = azurerm_logic_app_workflow.example.id

  body = <<BODY
                       {
                "inputs": {
                    "variables": [
                        {
                            "name": "travelTime",
                            "type": "integer",
                            "value": "@div(body('Get_route_and_travel_time_with_traffic')?['travelDurationTraffic'],60)"
                        }
                    ]
                },
                "runAfter": {
                    "Get_route_and_travel_time_with_traffic": [
                        "Succeeded"
                    ]
                },
                "type": "InitializeVariable"
            }
BODY
depends_on = [
  azurerm_logic_app_action_custom.action1
]
}
resource "azurerm_logic_app_action_custom" "condition" {
  name         = "If_travel_time_exceeds_limit"
  logic_app_id = azurerm_logic_app_workflow.example.id

  body = <<BODY
{
                            "actions": {
                                "Send_email_with_travel_time": {
                                    "runAfter": {},
                                    "type": "ApiConnection",
                                    "inputs": {
                                        "body": {
                                            "Body": "<p>Add extra travel time (minutes): @{sub(variables('travelTime'),15)}</p>",
                                            "Subject": "Current travel time (minutes): @{variables('travelTime')}",
                                            "To": "[email protected]"
                                        },
                                        "host": {
                                            "connection": {
                                                "name": "${local.office365connectionid}"
                                            }
                                        },
                                        "method": "post",
                                        "path": "/v2/Mail"
                                    }
                                }
                            },
                            "runAfter": {
                                "Create_variable_to_store_travel_time": [
                                    "Succeeded"
                                ]
                            },
                            "expression": {
                                "and": [
                                    {
                                        "greater": [
                                            "@variables('travelTime')",
                                            15
                                        ]
                                    }
                                ]
                            },
                            "type": "If"
                        }
BODY
depends_on = [
  azurerm_logic_app_action_custom.action2
]
}

Output:

enter image description here

enter image description here

enter image description here

Every thing gets deployed but the api connection gives error in the logic app as not found so you will have to configure that manually or by the solution I have mentioned in the other SO thread.

Upvotes: 6

Related Questions