-1

I am trying to automate the creation of a new Azure resource group, with storage and Azure function, from an admin Azure function. So whenever i get a new customer, i want to send a http request, with a company name, to my admin function, which in turn should create a new resource group with storage and blob trigger function.

So far i am able to send the http request, create all the resources and trigger the blob triggered function when i upload a file. I have had a bunch of problems uploading my python script, but have ended up adding it as a file property, as raw text.

Here is the bicep file i use to deploy the storage and function:

@description('Name of the company')
param companyName string

@description('Location for the resources')
param location string = resourceGroup().location

@description('Name of the storage account')
param storageAccountName string = '${uniqueString(companyName)}stacc'

@description('Name of the function app')
param functionAppName string = '${uniqueString(companyName)}funcApp'

var containerName = 'funcfiles'

resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
}

resource blobServices 'Microsoft.Storage/storageAccounts/blobServices@2023-01-01' = {
  parent: storageAccount
  name: 'default'
}

resource container 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = {
  parent: blobServices
  name: containerName
}

resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
  name: '${functionAppName}-plan'
  location: location
  kind: 'Linux'
  sku: {
    name: 'Y1'
    tier: 'Dynamic'
    size: 'Y1'
    family: 'Y'
    capacity: 0
  }
  properties: {
    reserved: true
  } 
}

resource functionApp 'Microsoft.Web/sites@2022-03-01' = {
  name: functionAppName
  location: location
  kind: 'functionapp,linux'
  properties: {
    serverFarmId: appServicePlan.id
    siteConfig: {
      pythonVersion: '3.10'
      linuxFxVersion: 'python|3.10'
      appSettings: [
        {
          name: 'AzureWebJobsStorage'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
        }
        {
          name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
        }
        {
          name: 'WEBSITE_CONTENTSHARE'
          value: toLower(functionAppName)
        }
        {
          name: 'FUNCTIONS_EXTENSION_VERSION'
          value: '~4'
        }
        {
          name: 'FUNCTIONS_WORKER_RUNTIME'
          value: 'python'
        }
        {
          name: 'AzureWebJobsFeatureFlags'
          value: 'EnableWorkerIndexing'
        }
      ]
    }
  }
}

resource blobTriggerFunction 'Microsoft.Web/sites/functions@2022-03-01' = {
  parent: functionApp
  name: 'BlobTrigger${functionAppName}'
  properties: {
    config: {
      bindings: [
        {
          name: 'myblob'
          type: 'blobTrigger'
          direction: 'in'
          path: containerName
          connection: 'AzureWebJobsStorage'
        }
      ]
      disabled: false
    }
    files:{
      '__init__.py': '''
import logging
import requests
import azure.functions as func

app = func.FunctionApp()

@app.blob_trigger(arg_name="myblob", path="funcfiles",
                               connection="AzureWebJobsStorage") 
def blob_trigger(myblob: func.InputStream):
    logging.info(f"File {myblob.name} was added to blob")

    API_URL = "****************"

    # use form data to upload files
    form_data = {
        "files": (myblob.name, myblob.read())
    }
    body_data = {
        'returnSourceDocuments': True
    }

    logging.info(f'Form data: {form_data}')
    logging.info(f'Body data: {body_data}')

    def query(form_data):
        response = requests.post(API_URL, files=form_data, data=body_data)
        return response.json()

    output = query(form_data)
    logging.info(f'Request send to api. Output: {output}')
      '''
    }
  }
}

The latest problem, and what I'm hoping to be the last problem, is ModuleNotFoundError. Which leads to my question: How can i add and run requirements.txt?

I did try to add the requirements under files as raw input, like ive done with init.py, but that didn't work When i create an azure function app with a blob trigger, using the vscode tool, there is a bunch of extra files created and deployed. Here is an example of my admin function:

Azure function files in vscode

And here is the function made with the above bicep file: Functions made with arm

The BobTigger is made manually in Azure Portal for comparison.

I want to add a requirement.txt, so i can use requests or other modules. Is this possible?

##################### EDIT ##############################

I have changed my bicep file, so i now use zip deployment instead. Here is the last part:

resource functionApp 'Microsoft.Web/sites@2022-03-01' = {
  name: functionAppName
  location: location
  kind: 'functionapp,linux'
  properties: {
    serverFarmId: appServicePlan.id
    siteConfig: {
      pythonVersion: '3.10'
      linuxFxVersion: 'python|3.10'
      appSettings: [
        {
          name: 'AzureWebJobsStorage'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
        }
        {
          name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
        }
        {
          name: 'WEBSITE_CONTENTSHARE'
          value: toLower(functionAppName)
        }
        {
          name: 'FUNCTIONS_EXTENSION_VERSION'
          value: '~4'
        }
        {
          name: 'FUNCTIONS_WORKER_RUNTIME'
          value: 'python'
        }
        {
          name: 'AzureWebJobsFeatureFlags'
          value: 'EnableWorkerIndexing'
        }
        {
          name: 'WEBSITE_RUN_FROM_PACKAGE'
          value: packageUri
        }
      ]
    }
  }
}

I created a new Azure function from the vscode template and zipped that whole project. The directory looks like this:

 FunctionProject/
 | - .venv/
 | - .vscode/
 | - function_app.py
 | - .funcignore
 | - host.json
 | - local.settings.json
 | - requirements.txt

I then put it into my blob storage and create a SAS url. This works and the blob function is registered, as long as i dont import a module. So this works and the portal shows the function:

import azure.functions as func
import logging

app = func.FunctionApp()

@app.function_name(name="BlobTrigger1")
@app.blob_trigger(arg_name="myblob", path="funcfiles",
                               connection="funcappprojectstorage_STORAGE") 
def blob_trigger(myblob: func.InputStream):
    API_URL = "*************"

    # use form data to upload files
    form_data = {
        "files": (myblob.name, myblob.read())
    }
    body_data = {
        'returnSourceDocuments': True
    }

    logging.info(f'Form data: {form_data}')
    logging.info(f'Body data: {body_data}')

But importing the request module like this:

import azure.functions as func
import requests
import logging

app = func.FunctionApp()

@app.function_name(name="BlobTrigger1")
@app.blob_trigger(arg_name="myblob", path="funcfiles",
                               connection="funcappprojectstorage_STORAGE") 
def blob_trigger(myblob: func.InputStream):
    API_URL = "*************"

    # use form data to upload files
    form_data = {
        "files": (myblob.name, myblob.read())
    }
    body_data = {
        'returnSourceDocuments': True
    }

    logging.info(f'Form data: {form_data}')
    logging.info(f'Body data: {body_data}')

Results in a function app without a registered blob triggered function

I am also able to spin it up locally and trigger the blob. It is just when it is uploaded to Azure that it doesn't work.

7
  • 1
    Have you tried uploading all files together as a zip file with the help of WEBSITE_RUN_FROM_PACKAGE app setting. @theproductivepickle Commented Aug 20, 2024 at 11:31
  • I haven't been able to find a good resource to follow. But maybe I need to look more into the documentation. So far the main questions about the zip deployment is: Do i just put the zip file in my admin storage? And does the zip just contain the host, requirements and function_app.py or do i add the .vscode which has the task.json as well? Let me know if you have a good python zip deployment resource Commented Aug 21, 2024 at 0:57
  • Have you tried uploading the zip deployment with Azure CLI by any chance! @theproductivepickle Commented Aug 21, 2024 at 14:09
  • Just tried and i run into same problem. I can upload the same simple template, but as soon as i add import requests, it doesn't register the trigger. I used cmd: "az functionapp deployment source config-zip -g a-demoResourceGroup -n funcapp --src zipdeploy.zip" Commented Aug 21, 2024 at 22:15
  • I will check in my environment and update you. @theproductivepickle Commented Aug 22, 2024 at 4:57

1 Answer 1

0

How can I add and run requirements.txt?

ModuleNotFoundError error occurs when the dependencies of a triggered function are not correctly configured and deployed to the function app after deploying the package.

In order to add and run the requirements.txt file (dependencies) along with the function_app.py file, you need to use func azure functionapp publish command as shown in the below format. It will install all the dependencies accordingly.

Refer MSDoc for the relevant information on your issue.

func azure functionapp publish newapsg --build remote

enter image description here

Once the remote build has succeeded, I was able to view all the necessary dependencies under Functions >> App files in the Portal. You can be able to make the required changes now.

enter image description here

I have also checked in kudu whether the files are correctly loaded, and it was working as expected.

enter image description here

Sign up to request clarification or add additional context in comments.

3 Comments

Is it possible to do without using the command line functions? My challenge is that i need to do it from a python script in Azure functions. I need to trigger an Azure function which does all the deployment automatically.
After a workaround on it, I found it is not directly possible to automate the deployment with python azure function trigger. @theproductivepickle
Is the issue resolved for you. @theproductivepickle

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.