Giter Club home page Giter Club logo

socless_integration_packager's Introduction

socless_integration_packager

serverless

$ npm install --save socless_integration_packager
# serverless.yml
plugins:
  - socless_integration_packager

A Serverless Framework plugin for packaging Python Lambda functions with only the dependencies they need.

This plugin makes it easy to manage function-level and service-level dependencies for your SOCless Integration, package it in a docker container that replicates the actual AWS Lambda environment, and zip it for deployment via Serverless.

Let's consider the following project structure

socless-slack/
├── common_files
│   ├── slack_helpers.py
│   └── common2.py
├── functions
│   ├── requirements.txt # with requests library
│   ├── slack_send_dialog
│   │     ├── lambda.py
│   │     └── requirements.txt
│   └── slack_send_message
│         ├── lambda.py
│         └── requirements.txt
└── serverless.yml

This project has:

  • two functions, slack_send_dialog and slack_send_message, each with their own requirements.txt files. slack_send_dialog's requirements.txt lists the requests pip package
  • Code common to both slack_send_dialog and slack_send_message in a directory named common_files
  • A top-level requirements.txt file with pip dependencies common to both functions, e.g slackclient & socless_python

This plugin will package your functions into individual zip files that look like:

├── lambda.py # function-level code
├── requirements.txt
├── slack_helpers.py # service-level code
├── common2.py
├── slackclient # service-level dependencies
├── slackclient-2.4.0.dist-info
├── socless
├── socless-1.5.0.dist-info
├── requests # function-level dependencies
└── requests-2.4.0.dist-info

So that the below code

import slack_helpers, common2, slackclient, requests, socless

in slack_send_dialog/lambda.py works like works like a charm!

The plugin packages your dependencies using a Docker Image that replicates your cloud providers environment, allowing you easily work with platform-dependent libraries like numpy.

The plugin handles the creation of the artifact zip files for your Serverless functions.

When serverless deploy is run, the plugin will:

  1. Create a build directory for each function
  2. Copy the appropriate function-level and service-level code you specify into each function's build directory
  3. Copy the build directories into a LambCI Docker Container (or any dockerfile of your choosing)
  4. Download the appropriate function-level and service-level pip dependencies into each function's build directory inside the container
  5. Create zip files of each functions build directory

The Serverless framework will then pickup each zip file and upload it to your provider.

Here's a simple serverless.yml configuration for this plugin, assuming the project structure above. For one of the functions we add -${opt:stage} to the name in order to append the stage to the function name

service: socless-slack

package:
    individually: true
    
plugins:
  - socless_integration_packager

custom:
  soclessPackager: # plugin configuration
    # buildDir: _build
    # requirementsFile: 'requirements.txt'
    # globalRequirements:
      - ./requirements.txt
    # globalIncludes:
      - ./common_files
    # cleanup: true

functions:
  slack_send_dialog:
    name: slack_send_dialog-${opt:stage}
    handler: lambda.handler
    package:
      include:
        - fucntions/slack_send_dialog
      artifact: ${self:custom.soclessPackager.buildDir}/slack_send_dialog.zip

  slack_send_message:
    name: slack_send_message
    handler: lambda.handler
    package:
      include:
        - functions/slack_send_message
      artifact: ${self:custom.soclessPackager.buildDir}/slack_send_message.zip

The plugin configurations are simple:

Configuration Description Optional?
buildDir Path to a build directory relative to project root, e.g. build No.
requirementsFile The name of the requirements file used for function-level requirements. All function-level requirements files must use the name specified here. Yes. Defaults to requirements.txt
globalRequirements A list of paths to files containing service-level pip requirements. Yes. Defaults to ["./functions/requirements.txt"]
globalIncludes A list of paths to folders containing service-level code files (i.e. code common to all functions). Only the folders contents will be packaged, not the folder itself. Paths to files are not currently supported. Yes Defaults to ["./common_files"]
useDocker Boolean indicating whether to package pip dependencies using Docker. Set this to true if your project uses platform-specific compiled libraries like numpy. Requires a Docker installation. Yes. Defaults to true
dockerImage The Docker image to use to compile functions if useDocker is set to true. Must be specified as repository:tag. If the image doesn't exist on the system, it will be downloaded. The initial download may take some time. Yes. Defaults to lambci/lambda:build-${provider.runtime}
containerName The desired name for the Docker container. Yes. Defaults to socless_integration_packager
abortOnPackagingErrors Boolean indicating whether you want to stop deployment when packaging errors are detected. Examples of scenarios that will cause packaging errors include: useDocker is enabled but the Docker service is not running, pip finds dependency mismatches, virtual environment errrors, etc.. When an error is detected, this will prompt via commandline to continue or abort deploy. Yes. Defaults to true

At the function level, you:

  • Specify name to give your function a name. The plugin uses the function's name as the name of the zip artifact
  • Use include to specify what function-level files you want to include in your artifact. Simply specifying the path to the function's folder will include every file in the folder in the function's zip artifact
  • Use artifact to tell Serverless where to find the zip artifact. The plugin creates the zip artifact for the function at buildDir/name.zip, so using ${self:custom.soclessPackager.buildDir}/[function-name-here].zip is advised.

At the package level, you may need to:

  • Specify the individually parameter as true to ensure that zip artifacts are generated properly. You may need this if you are getting file not found errors about your zip artifact.

Now, you may be wondering, doesn't the Serverless documentation say:

Serverless won't zip your service if [artifact] is configured and therefore exclude and include will be ignored. Either you use artifact or include / exclude.

Yes, that is correct and is actually awesome! Since Serverless ignores include/exclude silently when artifact is specified, it allows this plugin take advantage of the include property to provide you with a familiar interface for specifying function-level dependencies. So while this plugin uses include to determine what goes in your artifact, all Serverless cares about is the artifact that this plugin creates when it executes.

The last thing that your keen eye may have noticed from the example serverless.yml above is that handler is specified simply as lambda.handler not ${self:custom.soclessPackager.buildDir}/function/lambda.hadler or function/lambda.handler. This is because the plugin zips your artifacts such that /path/to/function is the root of the zip file. Combined with the fact that it uses pip install -t to download pip dependencies directly to the top level of the zip file, this makes imports significantly simpler for your project. Furthermore, since pip install -t downloads the actual pip package files into a folder, this plugin works without the need for virtualenv

socless_integration_packager's People

Contributors

noxasaxon avatar sonnens avatar

Watchers

James Cloos avatar  avatar

Forkers

syllogy sonnens

socless_integration_packager's Issues

Github clone errors shadowed on code

Hi,

There has been an issue on our side on what looks like temporarily errors while doing github cloning or pip installations were not properly handle by the integration packager and did not fail as expected as part of our continuous deployment process.

The output error we had on our side is:

Running command git clone -q https://github.com/twilio-labs/socless_python.git /tmp/pip-install-fg5kpmwk/socless_6448556d49db46b5bf79d535391cb0df
--
155 | Running command git checkout -q 58e37a80175642bb64c086459250bd4607e802ee
156 | WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))': /simple/idna/

WARNING: You are using pip version 21.0; however, version 22.0.3 is available.
--
158 | You should consider upgrading via the '/var/lang/bin/python3.7 -m pip install --upgrade pip' command.


___ERROR DETECTED, BEGIN STDOUT____
--
160 | Collecting socless
161 | Cloning https://github.com/twilio-labs/socless_python.git (to revision 1.5.0) to /tmp/pip-install-fg5kpmwk/socless_6448556d49db46b5bf79d535391cb0df
162 | Collecting requests
163 | Using cached requests-2.27.1-py2.py3-none-any.whl (63 kB)
164 | Collecting simplejson
165 | Using cached simplejson-3.17.6-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (130 kB)
166 | Collecting jinja2
167 | Using cached Jinja2-3.0.3-py3-none-any.whl (133 kB)
168 | Collecting idna<4,>=2.5
169 | Using cached idna-3.3-py3-none-any.whl (61 kB)
170 | Collecting charset-normalizer~=2.0.0
171 | Using cached charset_normalizer-2.0.12-py3-none-any.whl (39 kB)
172 | Collecting urllib3<1.27,>=1.21.1
173 | Using cached urllib3-1.26.8-py2.py3-none-any.whl (138 kB)
174 | Collecting certifi>=2017.4.17
175 | Using cached certifi-2021.10.8-py2.py3-none-any.whl (149 kB)
176 | Collecting MarkupSafe>=2.0
177 | Using cached MarkupSafe-2.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (25 kB)
178 | Building wheels for collected packages: socless
179 | Building wheel for socless (setup.py): started
180 | Building wheel for socless (setup.py): finished with status 'done'
181 | Created wheel for socless: filename=socless-1.5.0-py3-none-any.whl size=34011 sha256=9a629b658001f60cde002674cdedfe2ba8cc9f0200286fd91f304db0eba6db01
182 | Stored in directory: /tmp/pip-ephem-wheel-cache-ca47vj5g/wheels/4e/2b/b8/ccff8527eafff721eda5887083eb77921150e03a92bc5dd786
183 | Successfully built socless
184 | Installing collected packages: MarkupSafe, urllib3, simplejson, jinja2, idna, charset-normalizer, certifi, socless, requests
185 | Successfully installed MarkupSafe-2.1.0 certifi-2021.10.8 charset-normalizer-2.0.12 idna-3.3 jinja2-3.0.3 requests-2.27.1 simplejson-3.17.6 socless-1.5.0 urllib3-1.26.8
186 |  
187 | stty: when specifying an output style, modes may not be set
188 | /codebuild/output/src059378638/src/github.com/auth0/dar-socless-integrations/serverless/node_modules/readline-sync/lib/read.sh: 49: cannot create /dev/tty: No such device or address
189 | stty: invalid argument ‘-f’
190 | Try 'stty --help' for more information.
191 |  
192 | Error ---------------------------------------------------
193 |  
194 | Error: The current environment doesn't support interactive reading from TTY.

The error is triggering the request user confirmation which as it is within codebuild, it cant read from tty. An improvement also would be to make a variable for the user confirmation as it does not make sense on a pipeline scenario when there is no manual trigger for the job but we would prefer to fail the build under those circumstances.

Thanks for your help

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.