Search code examples
amazon-web-servicesaws-cloudformationaws-sam-cli

AWS SAM: Shared files across Lambda functions


I am working with AWS SAM (Serverless Application Model) to build Python 3.6 lambda code in an API Gateway setup. As such, I have a single template.yaml file that creates several Lambda functions. They are organized with the lambda functions each in their own sub-directory within the project. The lambda also share several common files which I keep in a shared folder.

project-home
 -lambda_a_dir
   -lambda_a.py
 -lambda_b_dir
   -lambda_b.py
 -shared_dir
   -shared.py

The problem is that while Pycharm can clearly see the shared.py, SAM cannot and refuses to recognize the shared files, with the following error: Unable to import module 'lambdaA': No module named 'shared' If I move a copy of the shared.py file into each lambda directory, both Pycharm and SAM are happy and I can build/deploy to AWS.
My question: how can I build the SAM template with the shared files living in the shared directory?
So far, I have tried:

  • Symbolic link and MacOS alias.
  • Various combinations of CodeUri alternatives
  • Local package with __init__ and setup.py. (I can't use a public package because the code is private and cannot not be put on a public repository.)

Here is my template file:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  lambdaA:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: ./lambda_a_dir/
      Handler: lambda_a.lambda_handler
      Runtime: python3.6
  lambdaB:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: ./lambda_b_dir/
      Handler: lambda_b.lambda_handler
      Runtime: python3.6

Solution

  • Following the recommendation from @Dunedan I created a Layers object for each lambda function with the shared code, this effectively added those routines to the PythonPath for those functions. I also added the following to the API template definition with the new Layers properties:

    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Resources:
      lambdaA:
        Type: AWS::Serverless::Function 
        Properties:
          CodeUri: ./lambda_a_dir/
          Handler: lambda_a.lambda_handler
          Runtime: python3.6
          Layers: 
            - arn:aws:lambda:us-west-1:012345678:layer:my_shared_zip:1
      lambdaB:
        Type: AWS::Serverless::Function 
        Properties:
          CodeUri: ./lambda_b_dir/
          Handler: lambda_b.lambda_handler
          Runtime: python3.6
          Layers: 
            - arn:aws:lambda:us-west-1:012345678:layer:my_shared_zip:1
    

    Note that the code needs to be zipped before it is uploaded and needs to have a directory structure of the following, with the code inside a directory with the name of the language. In this case since I was using Python, the code needed to be in the python directory, and the python directory was then zipped:

    my_shared_zip.zip
     -python
       -shared.py
       -other_shared.py
       -more_shared.py
    

    Last note. While ideally, this shared-python directory should be deployed directly by the sam deploy command into the Layer objects, I have found that support for Layers in the AWS SAM CLI is still so new and so buggy, that at this point its not functional. Hopefully in the coming months it will be fixed. In the meantime, I need to manually install new versions of the shared-zip file myself. Sigh.