serverless-python-requirements icon indicating copy to clipboard operation
serverless-python-requirements copied to clipboard

sls deploy function -f <function> does not work - TypeError: Cannot read property 'runtime' of undefined

Open aelsnz opened this issue 4 years ago • 11 comments

If you are using the latest serverless (I have tried 2.34 and above) with this plugin and try and update one function you get TypeError: Cannot read property 'runtime' of undefined

Any ideas why this fails if the plugin is enabled? This used to work well in earlier versions. Any help or ideas to solve this would be awesome.

Example output:

$ sls deploy function -f hello --stage ae --region ap-southeast-2

 Type Error ----------------------------------------------

  TypeError: Cannot read property 'runtime' of undefined
      at /Users/demo/test/node_modules/serverless-python-requirements/lib/pip.js:609:15
      at Array.filter (<anonymous>)
      at ServerlessPythonRequirements.installAllRequirements (/Users/demo/test/node_modules/serverless-python-requirements/lib/pip.js:608:8)
      at ServerlessPythonRequirements.tryCatcher (/Users/demo/test/node_modules/bluebird/js/release/util.js:16:23)
      at Promise._settlePromiseFromHandler (/Users/demo/test/node_modules/bluebird/js/release/promise.js:547:31)
      at Promise._settlePromise (/Users/demo/test/node_modules/bluebird/js/release/promise.js:604:18)
      at Promise._settlePromise0 (/Users/demo/test/node_modules/bluebird/js/release/promise.js:649:10)
      at Promise._settlePromises (/Users/demo/test/node_modules/bluebird/js/release/promise.js:729:18)
      at _drainQueueStep (/Users/demo/test/node_modules/bluebird/js/release/async.js:93:12)
      at _drainQueue (/Users/demo/test/node_modules/bluebird/js/release/async.js:86:9)
      at Async._drainQueues (/Users/demo/test/node_modules/bluebird/js/release/async.js:102:5)
      at Immediate.Async.drainQueues [as _onImmediate] (/Users/demo/test/node_modules/bluebird/js/release/async.js:15:14)
      at processImmediate (internal/timers.js:461:21)

     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com

  Your Environment Information ---------------------------
     Operating System:          darwin
     Node Version:              14.16.1
     Framework Version:         2.37.1
     Plugin Version:            4.5.3
     SDK Version:               4.2.2
     Components Version:        3.9.0

You can easily duplicate this using the example api - https://github.com/serverless/examples/tree/master/aws-python-rest-api with few small updates - see example serverless.yaml below.

service: test-api
frameworkVersion: '2'

plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    dockerizePip: true
    slim: true
    layer:
      compatibleRuntimes:
        - python3.8

provider:
  name: aws
  runtime: python3.8
  lambdaHashingVersion: '20201221'

package:
  individually: true
  patterns:
    - '!*.txt'
    - '!*.md'
    - '!*.json'
    - '!node_modules/**'

functions:
  hello:
    handler: handler.hello
    layers:
      - { Ref: PythonRequirementsLambdaLayer }
    events:
      - http:
          path: /
          method: get

Example requirements.txt with a module in there.

jsonpickle

Environment Details

serverless-python-requirements version: 5.1.1

Environment overview:
     Operating System:          darwin
     Node Version:              14.16.1
     Framework Version:         2.37.1
     Plugin Version:            4.5.3
     SDK Version:               4.2.2
     Components Version:        3.9.0

aelsnz avatar Apr 23 '21 01:04 aelsnz

I did some further testing and investigation and maybe this helps others to help figure out what is going wrong.

If you use:

package:
  individually: true

And you have enabled this plugin with Lamdba layers, you cannot deploy an individual function. If you do not set the above then you can deploy individual function but not all at once as you then get

  No file matches include / exclude patterns

Looking further at the code, the strange part is this, when an individual function is specified, example:

sls deploy function -f hello --stage ae --region ap-southeast-2

Lets look at index.js specific the targetFuncs() function...

...
  get targetFuncs() {
    let inputOpt = this.serverless.processedInput.options;
    return inputOpt.function
      ? [inputOpt.functionObj]
      : values(this.serverless.service.functions);
  }
...

This will return a "String" as the function name if an individual function is specified not an Array if all functions are to be deployed.

Now looking at ./lib/pip.js see the installAllREquirements() extract below where things are failing with the "filter"

function installAllRequirements() {
  // fse.ensureDirSync(path.join(this.servicePath, '.serverless'));
  // First, check and delete cache versions, if enabled
  checkForAndDeleteMaxCacheVersions(this.options, this.serverless);

  // Then if we're going to package functions individually...
  if (this.serverless.service.package.individually) {
    let doneModules = [];
    this.targetFuncs
      .filter((func) =>
        (func.runtime || this.serverless.service.provider.runtime).match(
          /^python.*/
        )
      )
...
...

If you look at this, we can see that if you have set package indiividually to true, this "targetFuncs" is expected to return an "Array" - as "filter" is used, but a string is passed in not an array.

Maybe this helps to solve this issue.

aelsnzhvr avatar May 13 '21 04:05 aelsnzhvr

I am also trying to figure out this. Really need to solve this.

EagleDangar avatar May 25 '21 15:05 EagleDangar

It's not that targetFuncs is returning a String, it's that it is returning an array of undefined. I am new to serverless, but I'm guessing that the options object previously had an attribute functionObj which is no longer there. The solution appears to be to replace [inputOpt.functionObj] with [this.serverless.service.functions[inputOpt.function]].

Having hacked that change in to my local version of the plugin, it no longer exhibits this error.

lxop avatar Jun 14 '21 06:06 lxop

Thank you - I have applied the change and it works!

aelsnzhvr avatar Jun 17 '21 21:06 aelsnzhvr

Is there any plan to bundle this fix into a release?

fnsfroskos avatar Oct 12 '21 17:10 fnsfroskos

@pgrzesik are there any plans to merge the PR for this? This has been ongoing for a while and it seems the fix has been ready for over a month now.

dalecampbell avatar Jan 08 '22 19:01 dalecampbell

Hey @dalecampbell, the PR is not complete as it doesn't include a test case, I've just wrote a comment about that, if we don't hear from the original author then we're open to other contributions.

pgrzesik avatar Jan 09 '22 15:01 pgrzesik

Any update @pgrzesik ?

dalecampbell avatar May 11 '22 13:05 dalecampbell

Hey @dalecampbell - no updates from the original author - I think at this point we should accept an alternative contributions if anyone would like to solve that problem

pgrzesik avatar May 11 '22 14:05 pgrzesik

hmm ran into the same trap. Thanks for the information.

using

sls deploy -f app

this.targetFuncs returns undefined

image

this is why :-/

inputOpt.functionObj is undefined....

image

pharindoko avatar May 24 '22 08:05 pharindoko

Sorry you've run into that issue @pharindoko

If anyone interested in taking over the PR that fixes it, we'll be happy to accept the contribution 🙌

pgrzesik avatar May 25 '22 17:05 pgrzesik