0
votes

I am trying to deploy an azure function app using an ARM template; however, I am unable to hit the function endpoints after deployment. I believe the issue is related to my ARM template, but I'm not sure what is wrong. The template passes validation & deploys successfully. I can even hit the deployed function and see the generic home page every function gets by default. The issue is, I cannot hit any of the functions in it without getting a 404. The function app code I am trying to deploy is just a new function project with a single "test" (GET/POST) function inside it (all auto generated by vscode).

If I deploy the function app using vscode & let vscode create the function app, it works fine. This leads me to believe the function app code is correct. If I deploy to my existing function (created using the ARM template), it deploys successfully, but I cannot hit any of the functions in it, only the home page.

I have tried to strip this ARM template down to the bare bones hoping to solve the issue, but I am at a loss. Has anyone else had this issue before or have any recommendations? I've been digging through Azure docs for hours with no luck. Any advice/input would be greatly appreciated! :)

Here is the template:

{
  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "env": {
      "type": "string",
      "allowedValues": [ "dev", "test", "prod" ],
      "defaultValue": "dev"
    },
    "name": {
      "type": "string",
      "defaultValue": ""
    }
  },
  "variables": {
    "resourceGroupName": "[concat(parameters('env'),'-ms-',parameters('name'))]"
  },
  "resources": [
    {
      "type": "Microsoft.Resources/resourceGroups",
      "apiVersion": "2020-10-01",
      "location": "East US",
      "name": "[variables('resourceGroupName')]"
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2020-10-01",
      "name": "[concat(variables('resourceGroupName'),'_deployment')]",
      "resourceGroup": "[variables('resourceGroupName')]",
      "dependsOn": [
        "[resourceId('Microsoft.Resources/resourceGroups',variables('resourceGroupName'))]"
      ],
      "properties": {
        "mode": "Incremental",
        "expressionEvaluationOptions": {
          "scope": "Inner"
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "variables": {
            "storageName": "[concat('storage',uniqueString(resourceGroup().id))]",
            //"insightsName": "[concat('insights',uniqueString(resourceGroup().id))]",
            "functionAppName": "[concat('function',uniqueString(resourceGroup().id))]"
          },
          "resources": [
            {
              "type": "Microsoft.Storage/storageAccounts",
              "apiVersion": "2021-01-01",
              "location": "[resourceGroup().location]",
              "name": "[variables('storageName')]",
              "kind": "StorageV2",
              "sku": {
                "name": "Standard_LRS"
              }
            },
            // {
            //   "type": "Microsoft.Insights/components",
            //   "apiVersion": "2015-05-01",
            //   "location": "[resourceGroup().location]",
            //   "name": "[variables('insightsName')]",
            //   "kind": "web",
            //   "properties": {
            //     "Application_Type": "web"
            //   }
            // },
            {
              "type": "Microsoft.Web/sites",
              "apiVersion": "2018-11-01",
              "location": "[resourceGroup().location]",
              "name": "[variables('functionAppName')]",
              "kind": "functionapp,linux",
              "dependsOn": [
                "[resourceId('Microsoft.Storage/storageAccounts',variables('storageName'))]"
              ],
              "properties": {
                "siteConfig": {
                  "appSettings": [
                    {
                      "name": "FUNCTIONS_EXTENSION_VERSION",
                      "value": "~3"
                    },
                    {
                      "name": "FUNCTIONS_WORKER_RUNTIME",
                      "value": "node"
                    },
                    {
                      "name": "AzureWebJobsStorage",
                      "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageName')), '2021-01-01').keys[0].value)]"
                    }
                    // {
                    //   "name": "APPINSIGHTS_INSTRUMENTATIONKEY",
                    //   "value": "[reference(variables('insightsName')).InstrumentationKey]"
                    // },
                    // {
                    //   "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
                    //   "value": "[reference(variables('insightsName')).ConnectionString]"
                    // }
                  ]
                  // "use32BitWorkerProcess": false,
                  // "minTlsVersion": "1.2",
                  // "http20Enabled": true,
                  // "ftpsState": "Disabled"
                },
                // "httpsOnly": true,
                "reserved": true
              }
            }
          ],
          "outputs": {
            "functionName": {
              "type": "string",
              "value": "[variables('functionAppName')]"
            }
          }
        }
      }
    }
  ],
  "outputs": {
    "functionName": {
      "type": "string",
      "value": "[reference(concat(variables('resourceGroupName'),'_deployment')).outputs.functionName.value]"
    }
  }
}
1
So, it looks like this template is creating the function app resource in Azure, but are you actually deploying your code to it? - Jason P
Hey Jason, thanks for the feedback! Yes, I am. I currently have it configured in the devops pipeline, which I believe is working. I also tried using the vscode functions extension which lets me deploy it directly from vscode. Both methods deploy successfully, but I cannot hit the functions. I can however hit the function app homepage, just not the functions inside it. - spyter
If you go to the function app resource in the Azure portal and click on the "Functions" or "App Files" menu options, do you see anything listed? - Jason P
Functions - It says editing functions in the AZ portal is not supported for linux consumption function apps. App Files - host.json, nothing else My project has a single "test" function (auto generated in vscode). It's not listed. This is the same result when deploying from vscode or through the pipeline. - spyter
@spyter According to your template, it seam that you do not put your function in one plan. - Jim Xu

1 Answers

0
votes

Ok, so I finally figured out what was going on. It was not ARM template related, even though I thought it was. I think all my attempts to troubleshoot things had led me down a rabbit hole of changes that made it appear to be ARM related.

Perhaps I missed this in the documentation, or perhaps it's not clear, but when building functions using ts/node, you need to include the host.json, dist folder & node_modules folder in the deployment zip file. I was only including the dist folder in my pipeline, which was the issue. I eventually added the host.json file for troubleshooting purposes, but it didn't work still because of the missing node_modules folder.

I have decided to include my CI pipeline yml code below for anyone else who might be having issues. Hopefully it helps! And, thanks to everyone in the replies that tried to help me. I really appreciate it! :)

# Node.js with gulp
# Build a Node.js project using the gulp task runner.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript

trigger:
- main

pool:
  vmImage: ubuntu-latest

steps:
- task: NodeTool@0
  inputs:
    versionSpec: '14.x'
  displayName: 'install node.js'

- script: |
    npm install
    npm run build 
  displayName: 'npm install & build' 

- task: ArchiveFiles@2
  inputs:
    rootFolderOrFile: '.'
    includeRootFolder: false
    archiveType: 'zip'
    archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
    replaceExistingArchive: true
  displayName: 'archiving dist folder'

- task: PublishBuildArtifacts@1
  inputs:
    PathtoPublish: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
    ArtifactName: 'drop'
    publishLocation: 'Container'
  displayName: 'dropping artifact'