Logic Apps deployment template extractor Connections update

An exciting update is now released, you who have used the Logic Apps Deployment Template Creator know that the support for connections have been poor. But know we have released an update that handles all connections, regardless if they are connected via gateway or not the needed parameters are generated and in the end populated to the parameters file. Still all parameters are needed to be set manually but automation of this is next step in this area. The files are then redeployable right away and we can move the files to VSTS for source control and for seting up release pipelines.

API connections Samples:

First off we take a SQL Azure instnance and create a Logic App that lists the content of a table (simple start).

Extracting this Logic App with the Template Creator and powershell will generate the following read more about how to extract logic apps with powershell and deployment template creator.:

Parameters: All Azure SQL Connections are extracted and presented, all but the securestring parameters (username and password) are autopopulated with the values on the exporter Logic App and API Connection.

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "logicAppName": {
      "value": "SQLAzure"
    },
    "logicAppLocation": {
      "value": "[resourceGroup().location]"
    },
    "sql-1_name": {
      "value": "sql-1"
    },
    "sql-1_displayName": {
      "value": "SQL Azure"
    },
    "sql-1_server": {
      "value": "dummyserverone.database.windows.net"
    },
    "sql-1_database": {
      "value": "dummydatabase"
    },
    "sql-1_username": {
      "value": ""
    },
    "sql-1_password": {
      "value": ""
    }
  }
}

Logic App:

 {
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "logicAppName": {
      "type": "string",
      "defaultValue": "SQLAzure",
      "metadata": {
        "description": "Name of the Logic App."
      }
    },
    "logicAppLocation": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "allowedValues": [
        "[resourceGroup().location]",
        "eastasia",
        "southeastasia",
        "centralus",
        "eastus",
        "eastus2",
        "westus",
        "northcentralus",
        "southcentralus",
        "northeurope",
        "westeurope",
        "japanwest",
        "japaneast",
        "brazilsouth",
        "australiaeast",
        "australiasoutheast",
        "westcentralus",
        "westus2"
      ],
      "metadata": {
        "description": "Location of the Logic App."
      }
    },
    "sql-1_name": {
      "type": "string",
      "defaultValue": "sql-1"
    },
    "sql-1_displayName": {
      "type": "string",
      "defaultValue": "SQL Azure"
    },
    "sql-1_server": {
      "type": "string",
      "defaultValue": "dummyserverone.database.windows.net",
      "metadata": {
        "description": "SQL server name"
      }
    },
    "sql-1_database": {
      "type": "string",
      "defaultValue": "dummydatabase",
      "metadata": {
        "description": "SQL database name"
      }
    },
    "sql-1_username": {
      "type": "securestring",
      "defaultValue": "",
      "metadata": {
        "description": "Username credential"
      }
    },
    "sql-1_password": {
      "type": "securestring",
      "defaultValue": "",
      "metadata": {
        "description": "Password credential"
      }
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Logic/workflows",
      "apiVersion": "2016-06-01",
      "name": "[parameters('logicAppName')]",
      "location": "[parameters('logicAppLocation')]",
      "dependsOn": [
        "[resourceId('Microsoft.Web/connections', parameters('sql-1_name'))]"
      ],
      "properties": {
        "definition": {
          "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "$connections": {
              "defaultValue": {},
              "type": "Object"
            }
          },
          "triggers": {
            "manual": {
              "type": "Request",
              "kind": "Http",
              "inputs": {
                "schema": {}
              }
            }
          },
          "actions": {
            "Get_rows": {
              "runAfter": {},
              "type": "ApiConnection",
              "inputs": {
                "host": {
                  "connection": {
                    "name": "@parameters('$connections')['sql_1']['connectionId']"
                  }
                },
                "method": "get",
                "path": "/datasets/default/tables/@{encodeURIComponent(encodeURIComponent('[SalesLT].[Customer]'))}/items"
              }
            }
          },
          "outputs": {}
        },
        "parameters": {
          "$connections": {
            "value": {
              "sql_1": {
                "id": "[concat(subscription().id,'/providers/Microsoft.Web/locations/', parameters('logicAppLocation'), '/managedApis/sql')]",
                "connectionId": "[resourceId('Microsoft.Web/connections', parameters('sql-1_name'))]",
                "connectionName": "[parameters('sql-1_name')]"
              }
            }
          }
        }
      }
    },
    {
      "type": "Microsoft.Web/connections",
      "apiVersion": "2016-06-01",
      "location": "[parameters('logicAppLocation')]",
      "name": "[parameters('sql-1_name')]",
      "properties": {
        "api": {
          "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', parameters('logicAppLocation'), '/managedApis/', 'sql')]"
        },
        "displayName": "[parameters('sql-1_displayName')]",
        "parameterValues": {
          "server": "[parameters('sql-1_server')]",
          "database": "[parameters('sql-1_database')]",
          "username": "[parameters('sql-1_username')]",
          "password": "[parameters('sql-1_password')]"
        }
      }
    }
  ],
  "outputs": {}
}

If you add the sql username and password this will be ready for deployment, creating/updating the API Connection and creating/Updating the Logic App.

Redeploying this with username/password and changing the Logic App name to SQLAzureFromVS and API Connection name to sql-2 to will create a new Logix App and a new API Connection and link them so they are ready to be used right away!

And the new API Connection is shown in the API Connections blade.

If this would have been a SQL Connector usign Gateway there would be some differences but only on the API Connection and the parameters file. The API Connection will then have a Gatway object in the parameterValues object.

{
  "type": "Microsoft.Web/connections",
  "apiVersion": "2016-06-01",
  "location": "[parameters('logicAppLocation')]",
  "name": "[parameters('sql')]",
  "properties": {
    "api": {
      "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', parameters('logicAppLocation'), '/managedApis/', 'sql')]"
    },
    "displayName": "[parameters('sqldisplayName')]",
    "parameterValues": {
      "server": "[parameters('sql_server')]",
      "database": "[parameters('sql_database')]",
      "authType": "[parameters('sql_authType')]",
      "username": "[parameters('sql_username')]",
      "password": "[parameters('sql_password')]",
      "gateway": {
        "id": "[concat('subscriptions/',subscription().subscriptionId,'/resourceGroups/',parameters('sql_gatewayresourcegroup'),'/providers/Microsoft.Web/connectionGateways/',parameters('sql_gatewayname'))]"
      }
    }
  }
}

And the parameter file will contain the two new parameters sql_gatewayname that should contain the name of the Gateway and sql_gatewayresourcegroup parameter that should contain the resource group where the gateway is deployed in.

"sql_gatewayname": {
  "type": "string",
  "defaultValue": "Malos-LogicApp2015"
},
"sql_gatewayresourcegroup": {
  "type": "string",
  "defaultValue": "OnPremDataGateway"
}

As above, set the credentials, change the database setting to your new ones, point out the gateway via name and resource group and we are good to go.

Mixing multiple connections is not a problem, here is a sample on how it will look like when using both Storage and Service Bus Connectors. Simple Sample bellow saving to storage and then publish on service bus queue.

As you can see bellow the extractor will generate the needed connectors and it’s parameters.

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "logicAppName": {
      "type": "string",
      "defaultValue": "ServicebusAndStorage",
      "metadata": {
        "description": "Name of the Logic App."
      }
    },
    "logicAppLocation": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "allowedValues": [
        "[resourceGroup().location]",
        "eastasia",
        "southeastasia",
        "centralus",
        "eastus",
        "eastus2",
        "westus",
        "northcentralus",
        "southcentralus",
        "northeurope",
        "westeurope",
        "japanwest",
        "japaneast",
        "brazilsouth",
        "australiaeast",
        "australiasoutheast",
        "westcentralus",
        "westus2"
      ],
      "metadata": {
        "description": "Location of the Logic App."
      }
    },
    "azureblob_name": {
      "type": "string",
      "defaultValue": "azureblob"
    },
    "azureblob_displayName": {
      "type": "string",
      "defaultValue": "dummy storage"
    },
    "azureblob_accountName": {
      "type": "string",
      "defaultValue": "dymmystorage",
      "metadata": {
        "description": "Name of the storage account the connector should use."
      }
    },
    "azureblob_accessKey": {
      "type": "securestring",
      "defaultValue": "",
      "metadata": {
        "description": "Specify a valid primary/secondary storage account access key."
      }
    },
    "servicebus_name": {
      "type": "string",
      "defaultValue": "servicebus"
    },
    "servicebus_displayName": {
      "type": "string",
      "defaultValue": "dummy service bus"
    },
    "servicebus_connectionString": {
      "type": "securestring",
      "defaultValue": "",
      "metadata": {
        "description": "Azure Service Bus Connection String"
      }
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Logic/workflows",
      "apiVersion": "2016-06-01",
      "name": "[parameters('logicAppName')]",
      "location": "[parameters('logicAppLocation')]",
      "dependsOn": [
        "[resourceId('Microsoft.Web/connections', parameters('azureblob_name'))]",
        "[resourceId('Microsoft.Web/connections', parameters('servicebus_name'))]"
      ],
      "properties": {
        "definition": {
          "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "$connections": {
              "defaultValue": {},
              "type": "Object"
            }
          },
          "triggers": {
            "manual": {
              "type": "Request",
              "kind": "Http",
              "inputs": {
                "schema": {}
              }
            }
          },
          "actions": {
            "Create_blob": {
              "runAfter": {},
              "type": "ApiConnection",
              "inputs": {
                "body": "hej hej",
                "host": {
                  "connection": {
                    "name": "@parameters('$connections')['azureblob']['connectionId']"
                  }
                },
                "method": "post",
                "path": "/datasets/default/files",
                "queries": {
                  "folderPath": "/orders",
                  "name": "@{guid()}.txt"
                }
              }
            },
            "Send_message": {
              "runAfter": {
                "Create_blob": [
                  "Succeeded"
                ]
              },
              "type": "ApiConnection",
              "inputs": {
                "body": {
                  "ContentData": "@{base64('hej hej')}",
                  "ContentType": "text"
                },
                "host": {
                  "connection": {
                    "name": "@parameters('$connections')['servicebus']['connectionId']"
                  }
                },
                "method": "post",
                "path": "/@{encodeURIComponent('ordersqueue')}/messages",
                "queries": {
                  "systemProperties": "None"
                }
              }
            }
          },
          "outputs": {}
        },
        "parameters": {
          "$connections": {
            "value": {
              "azureblob": {
                "id": "[concat(subscription().id,'/providers/Microsoft.Web/locations/', parameters('logicAppLocation'), '/managedApis/azureblob')]",
                "connectionId": "[resourceId('Microsoft.Web/connections', parameters('azureblob_name'))]",
                "connectionName": "[parameters('azureblob_name')]"
              },
              "servicebus": {
                "id": "[concat(subscription().id,'/providers/Microsoft.Web/locations/', parameters('logicAppLocation'), '/managedApis/servicebus')]",
                "connectionId": "[resourceId('Microsoft.Web/connections', parameters('servicebus_name'))]",
                "connectionName": "[parameters('servicebus_name')]"
              }
            }
          }
        }
      }
    },
    {
      "type": "Microsoft.Web/connections",
      "apiVersion": "2016-06-01",
      "location": "[parameters('logicAppLocation')]",
      "name": "[parameters('servicebus_name')]",
      "properties": {
        "api": {
          "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', parameters('logicAppLocation'), '/managedApis/', 'servicebus')]"
        },
        "displayName": "[parameters('servicebus_displayName')]",
        "parameterValues": {
          "connectionString": "[parameters('servicebus_connectionString')]"
        }
      }
    },
    {
      "type": "Microsoft.Web/connections",
      "apiVersion": "2016-06-01",
      "location": "[parameters('logicAppLocation')]",
      "name": "[parameters('azureblob_name')]",
      "properties": {
        "api": {
          "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', parameters('logicAppLocation'), '/managedApis/', 'azureblob')]"
        },
        "displayName": "[parameters('azureblob_displayName')]",
        "parameterValues": {
          "accountName": "[parameters('azureblob_accountName')]",
          "accessKey": "[parameters('azureblob_accessKey')]"
        }
      }
    }
  ],
  "outputs": {}
}

The parameter file will look like following, and only the accesskey for blob and the connection string is not autopopulated with current values.

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "logicAppName": {
      "value": "ServicebusAndStorage"
    },
    "logicAppLocation": {
      "value": "[resourceGroup().location]"
    },
    "azureblob_name": {
      "value": "azureblob"
    },
    "azureblob_displayName": {
      "value": "dummy storage"
    },
    "azureblob_accountName": {
      "value": "dymmystorage"
    },
    "azureblob_accessKey": {
      "value": ""
    },
    "servicebus_name": {
      "value": "servicebus"
    },
    "servicebus_displayName": {
      "value": "dummy service bus"
    },
    "servicebus_connectionString": {
      "value": ""
    }
  }
}

Key Vault integration

A small step has taken for KeyVault integration, read more about using KeyVault with ARM deployments here. When using the Get-ParameterTemplate operation there is a new parameter -KeyVault, it can be either “None” or “Static” and when used with Static as example code bellow a static reference will be generated for KeyVault integration. And when deployed the value stored in the secret will be used as the parameter value, separating secrets from deployment templats.

Get-ParameterTemplate -TemplateFile $filenname -KeyVault Static | Out-File $filennameparam

With one of our earlier sample it will look like this when used with Static:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "logicAppName": {
      "value": "SQLInsertOnPrem"
    },
    "logicAppLocation": {
      "value": "[resourceGroup().location]"
    },
    "sql_name": {
      "value": "sql"
    },
    "sql_displayName": {
      "value": "SQL server OnPrem"
    },
    "sql_server": {
      "value": "."
    },
    "sql_database": {
      "value": "InvoiceDatabase"
    },
    "sql_authType": {
      "value": "windows"
    },
    "sql_username": {
      "reference": {
        "keyVault": {
          "id": "/subscriptions/{subscriptionid}/resourceGroups/{resourcegroupname}/providers/Microsoft.KeyVault/vaults/{vault-name}"
        },
        "secretName": "sql_username"
      }
    },
    "sql_password": {
      "reference": {
        "keyVault": {
          "id": "/subscriptions/{subscriptionid}/resourceGroups/{resourcegroupname}/providers/Microsoft.KeyVault/vaults/{vault-name}"
        },
        "secretName": "sql_password"
      }
    },
    "sql_gatewayname": {
      "value": "Malos-LogicApp2015"
    },
    "sql_gatewayresourcegroup": {
      "value": "OnPremDataGateway"
    }
  }
}

Replace the {bracketed} values with the correct ones, secret name is the value of the secret and can also be replace, for simplicity we generate it tot the same value as the parameter.

{subscriptionid} = your subscriptionid

{resourcegroupname} = the resourcegroup where the keyvault is deployed

{vault-name} = the name of the vault

Or just copy the resourceid found at the properties blade on the KeyVault as the image shows.

We think that these features has really improved the experience and ease of use with the Logic App template Creator so I hope you like it.

I strongly recomend you to try it and help out evolving it, more updates coming so stay tuned!

https://github.com/jeffhollan/LogicAppTemplateCreator

Posted in: •Logic Apps  •Integration  | Tagged: •DTAP  •Logic Apps  •Deployments  •Azure  •ARM  •ARM Template