Skip to content

Better mixed runtime & function deploy handling #180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 26, 2018
Merged

Conversation

dschep
Copy link
Contributor

@dschep dschep commented Apr 23, 2018

fixes #161 and fixes #179

Could you test this out @icj217 & @AndrewFarley?

npm i UnitedIncome/serverless-python-requirements#issues-161-179

@icj217
Copy link

icj217 commented Apr 23, 2018

@dschep Tried it out and here's what I get (historical-validation and convert-ens-format are both python functions)
Function definition:

custom:
   pythonRequirements:
    dockerizePip: 'non-linux'

package:
  individually: true
  excludeDevDependencies: false

functions:
  historical-validation:
    handler: historical-validation.handler (also tried functions/historical-validation/historical-validation.handler)
    runtime: python3.6
    description: Historical validator
    timeout: 300
    module: functions/historical-validation

Deployment:

craigburdulis@Craig-Burdulis-MacBook-Air:~/Documents/Projects/hsx-panel-qa$ SLS_DEBUG=* sls deploy --function historical-validation
Serverless: Load command run
Serverless: Load command config
Serverless: Load command config:credentials
Serverless: Load command create
Serverless: Load command install
Serverless: Load command package
Serverless: Load command deploy
Serverless: Load command deploy:function
Serverless: Load command deploy:list
Serverless: Load command deploy:list:functions
Serverless: Load command invoke
Serverless: Load command invoke:local
Serverless: Load command info
Serverless: Load command logs
Serverless: Load command login
Serverless: Load command logout
Serverless: Load command metrics
Serverless: Load command print
Serverless: Load command remove
Serverless: Load command rollback
Serverless: Load command rollback:function
Serverless: Load command slstats
Serverless: Load command plugin
Serverless: Load command plugin
Serverless: Load command plugin:install
Serverless: Load command plugin
Serverless: Load command plugin:uninstall
Serverless: Load command plugin
Serverless: Load command plugin:list
Serverless: Load command plugin
Serverless: Load command plugin:search
Serverless: Load command emit
Serverless: Load command config
Serverless: Load command config:credentials
Serverless: Load command rollback
Serverless: Load command rollback:function
Serverless: Load command invoke
Serverless: Load command invoke:stepf
Serverless: Load command requirements
Serverless: Load command requirements:clean
Serverless: Load command requirements:install
Serverless: Invoke deploy
Serverless: Invoke deploy:function
Serverless: Installing requirements of requirements.txt in .serverless...
Serverless: Docker Image: lambci/lambda:build-python3.6
Serverless: Installing requirements of functions/historical-validation/requirements.txt in .serverless/functions/historical-validation...
Serverless: Docker Image: lambci/lambda:build-python3.6
Serverless: Installing requirements of functions/convert-ens-format/requirements.txt in .serverless/functions/convert-ens-format...
Serverless: Docker Image: lambci/lambda:build-python3.6
Serverless: Invoke package:function
Serverless: Packaging function: historical-validation...
Serverless: /Users/craigburdulis/Documents/Projects/hsx-panel-qa/.serverless/historical-validation.zip
Serverless: Injecting required Python packages to package...

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

  Cannot read property 'artifact' of undefined

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

  Stack Trace --------------------------------------------

TypeError: Cannot read property 'artifact' of undefined
    at BbPromise.resolve.filter.map.map.func (/Users/craigburdulis/Documents/Projects/hsx-panel-qa/node_modules/serverless-python-requirements/lib/inject.js:98:40)
From previous event:
    at PluginManager.invoke (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:372:22)
    at PluginManager.spawn (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:390:17)
    at Deploy.BbPromise.bind.then.then (/usr/local/lib/node_modules/serverless/lib/plugins/deploy/deploy.js:118:50)
From previous event:
    at Object.before:deploy:deploy [as hook] (/usr/local/lib/node_modules/serverless/lib/plugins/deploy/deploy.js:113:10)
    at BbPromise.reduce (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:372:55)
From previous event:
    at PluginManager.invoke (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:372:22)
    at PluginManager.run (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:403:17)
    at variables.populateService.then (/usr/local/lib/node_modules/serverless/lib/Serverless.js:102:33)
    at runCallback (timers.js:672:20)
    at tryOnImmediate (timers.js:645:5)
    at processImmediate [as _immediateCallback] (timers.js:617:5)
From previous event:
    at Serverless.run (/usr/local/lib/node_modules/serverless/lib/Serverless.js:89:74)
    at serverless.init.then (/usr/local/lib/node_modules/serverless/bin/serverless:42:50)

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Forums:        forum.serverless.com
     Chat:          gitter.im/serverless/serverless

  Your Environment Information -----------------------------
     OS:                     darwin
     Node Version:           6.11.0
     Serverless Version:     1.26.1

@icj217
Copy link

icj217 commented Apr 23, 2018

It does work, however, when I set individually to false.

@dschep
Copy link
Contributor Author

dschep commented Apr 23, 2018

yup. good catch. i'm able to reproduce the issue.

@icj217
Copy link

icj217 commented Apr 23, 2018

Deploying node.js functions now works as well when individually set to false.

@AndrewFarley
Copy link
Contributor

Checked this against three of my codebases with a variety of configs, worked fine, passed all my codebases' CI-related tests. Glanced at the code also, seems good. Much appreciated. Before merging I would remove that erroneous console.log of artifacts.

Of note: None of mine had the error like yours above with or without individually packaging. Might be a difference in the version of NodeJS (I'm using 6.13), but it should be pretty easy to fix (checking typeof, or so).

@dschep
Copy link
Contributor Author

dschep commented Apr 23, 2018

Updated. Give it another shot @icj217. Glad to hear it works for you @AndrewFarley!

@AndrewFarley
Copy link
Contributor

AndrewFarley commented Apr 23, 2018

Ahh @dschep warning do not merge... single function deploys is when that artifact problem occurs. I overlooked that in my brief tests since I haven't been able to do them in a while. Confirmed that problem occurs when using single function deploys, and confirmed that problem is gone now with your latest patch... but re-testing a bit now... and in my re-testing when deploying a single function I get major failures. The ZIP file we upload is now completely corrupt/invalid. It doesn't expand when re-downloaded from the Lambda console. So, something is super wrong with single function deploys. The package size looks alright, but something with the packager is corrupting the .zip (for me).

On a side note: I'm so not used to waiting for requirements to compile any more with my caching MR i've been using exclusively everywhere. This testing took forever

@AndrewFarley
Copy link
Contributor

@dschep See pastebin if it helps: https://pastebin.com/cYPWDVKY

@dschep
Copy link
Contributor Author

dschep commented Apr 23, 2018

Thanks for the warning @AndrewFarley. I'll have to really (as in actually test the deployed services) when i get time

lib/inject.js Outdated
@@ -107,14 +107,14 @@ function injectAllRequirements() {
.map(func =>
injectRequirements(
path.join('.serverless', func.module, 'requirements'),
func.package.artifact,
func.package ? func.package.artifact : artifact,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This did not fix the issue with doing a individually: true deployment. It complains about line 97.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated line 97 too.

@icj217
Copy link

icj217 commented Apr 23, 2018

Just tested out f4390b2 but it seems like when setting individually: true I'm getting the same error:

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

  Cannot read property 'artifact' of undefined

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

  Stack Trace --------------------------------------------

TypeError: Cannot read property 'artifact' of undefined
    at BbPromise.resolve.filter.map.map.func (/Users/craigburdulis/Documents/Projects/hsx-panel-qa/node_modules/serverless-python-requirements/lib/inject.js:97:40)
From previous event:
    at PluginManager.invoke (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:372:22)
    at PluginManager.spawn (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:390:17)
    at Deploy.BbPromise.bind.then.then (/usr/local/lib/node_modules/serverless/lib/plugins/deploy/deploy.js:118:50)
From previous event:
    at Object.before:deploy:deploy [as hook] (/usr/local/lib/node_modules/serverless/lib/plugins/deploy/deploy.js:113:10)
    at BbPromise.reduce (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:372:55)
From previous event:
    at PluginManager.invoke (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:372:22)
    at PluginManager.run (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:403:17)
    at variables.populateService.then (/usr/local/lib/node_modules/serverless/lib/Serverless.js:102:33)
    at runCallback (timers.js:672:20)
    at tryOnImmediate (timers.js:645:5)
    at processImmediate [as _immediateCallback] (timers.js:617:5)
From previous event:
    at Serverless.run (/usr/local/lib/node_modules/serverless/lib/Serverless.js:89:74)

@icj217
Copy link

icj217 commented Apr 23, 2018

Now it's saying:

ReferenceError: artifact is not defined
    at BbPromise.resolve.filter.map.map.func (/Users/craigburdulis/Documents/Projects/hsx-panel-qa/node_modules/serverless-python-requirements/lib/inject.js:97:67)
From previous event:
    at PluginManager.invoke (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:372:22)
    at PluginManager.spawn (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:390:17)
    at Deploy.BbPromise.bind.then.then (/usr/local/lib/node_modules/serverless/lib/plugins/deploy/deploy.js:118:50)
From previous event:
    at Object.before:deploy:deploy [as hook] (/usr/local/lib/node_modules/serverless/lib/plugins/deploy/deploy.js:113:10)
    at BbPromise.reduce (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:372:55)
From previous event:
    at PluginManager.invoke (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:372:22)
    at PluginManager.run (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:403:17)
    at variables.populateService.then (/usr/local/lib/node_modules/serverless/lib/Serverless.js:102:33)
    at runCallback (timers.js:672:20)
    at tryOnImmediate (timers.js:645:5)
    at processImmediate [as _immediateCallback] (timers.js:617:5)
From previous event:
    at Serverless.run (/usr/local/lib/node_modules/serverless/lib/Serverless.js:89:74)
    at serverless.init.then (/usr/local/lib/node_modules/serverless/bin/serverless:42:50)

@dschep
Copy link
Contributor Author

dschep commented Apr 23, 2018

oh yeah. duh. even the linter caught that. can't go reusing that same variable name. Updated again.

@icj217
Copy link

icj217 commented Apr 23, 2018

@dschep Now its line 99. Seems like the func.package does not exist yet when doing individual packaging.

TypeError: Cannot set property 'artifact' of undefined
    at BbPromise.resolve.filter.map.map.func (/Users/craigburdulis/Documents/Projects/hsx-panel-qa/node_modules/serverless-python-requirements/lib/inject.js:99:33)
From previous event:
    at PluginManager.invoke (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:372:22)
    at PluginManager.spawn (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:390:17)
    at Deploy.BbPromise.bind.then.then (/usr/local/lib/node_modules/serverless/lib/plugins/deploy/deploy.js:118:50)
From previous event:
    at Object.before:deploy:deploy [as hook] (/usr/local/lib/node_modules/serverless/lib/plugins/deploy/deploy.js:113:10)
    at BbPromise.reduce (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:372:55)
From previous event:
    at PluginManager.invoke (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:372:22)
    at PluginManager.run (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:403:17)
    at variables.populateService.then (/usr/local/lib/node_modules/serverless/lib/Serverless.js:102:33)
    at runCallback (timers.js:672:20)
    at tryOnImmediate (timers.js:645:5)
    at processImmediate [as _immediateCallback] (timers.js:617:5)
From previous event:
    at Serverless.run (/usr/local/lib/node_modules/serverless/lib/Serverless.js:89:74)
    at serverless.init.then (/usr/local/lib/node_modules/serverless/bin/serverless:42:50)

@dschep
Copy link
Contributor Author

dschep commented Apr 23, 2018

Hmm. weird. I was able to deploy one of the test services before. but now when i try the following I am at getting the errors @AndrewFarley reported.

git clone https://github.com/UnitedIncome/serverless-python-requirements
cd serverless-python-requirements
git checkout issues-161-179
cd tests/base
npm i $(npm pack ../..)
sls deploy --individually
sls deploy --individually -f hello
sls deploy --individually -f hello3

@dschep
Copy link
Contributor Author

dschep commented Apr 23, 2018

Hmm.... @AndrewFarley sls deploy --individually -f hello after doing rm -r .serverless

@icj217
Copy link

icj217 commented Apr 24, 2018

@dschep Any update on my comment above?

@dschep
Copy link
Contributor Author

dschep commented Apr 24, 2018

sorry. nope. haven't had time to prioritize on this since we don't use this feature ourselves.

@dschep
Copy link
Contributor Author

dschep commented Apr 25, 2018

@AndrewFarley i merged #181 into this PR since i think it should address the corrupted zip issue

@AndrewFarley
Copy link
Contributor

@dschep Still got a problem when trying to deploy a single function with serverless deploy function -f funcname so can't validate if that fixes the corrupt zip bug. No other deploy problems when not deploying single functions though. See below...

Serverless: Excluding development dependencies...
Serverless: Injecting required Python packages to package...
 
  Type Error ---------------------------------------------
 
  path must be a string or Buffer
 
     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
 
  Stack Trace --------------------------------------------
 
TypeError: path must be a string or Buffer
    at TypeError (native)
    at fs.readFile (fs.js:305:11)
    at go$readFile (/Users/farley/PROJECTNAMEHERE/api_v2/node_modules/graceful-fs/graceful-fs.js:73:14)
    at Object.readFile (/Users/farley/PROJECTNAMEHERE/api_v2/node_modules/graceful-fs/graceful-fs.js:70:12)
    at Object.readFile (/Users/farley/PROJECTNAMEHERE/api_v2/node_modules/universalify/index.js:5:67)
    at injectRequirements (/Users/farley/PROJECTNAMEHERE/api_v2/node_modules/serverless-python-requirements/lib/inject.js:24:6)
    at ServerlessPythonRequirements.injectAllRequirements (/Users/farley/PROJECTNAMEHERE/api_v2/node_modules/serverless-python-requirements/lib/inject.js:118:12)
    at ServerlessPythonRequirements.BbPromise.bind.then.then (/Users/farley/PROJECTNAMEHERE/api_v2/node_modules/serverless-python-requirements/index.js:135:43)
    at runCallback (timers.js:672:20)
    at tryOnImmediate (timers.js:645:5)
    at processImmediate [as _immediateCallback] (timers.js:617:5)
 
  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Forums:        forum.serverless.com
     Chat:          gitter.im/serverless/serverless
 
  Your Environment Information -----------------------------
     OS:                     darwin
     Node Version:           6.12.3
     Serverless Version:     1.26.0

@icj217
Copy link

icj217 commented Apr 25, 2018

@dschep Seeing the same thing as @AndrewFarley

@AndrewFarley
Copy link
Contributor

AndrewFarley commented Apr 25, 2018

@dschep Isn't this still the upstream problem of the artifact not being set properly...? Just tried upgrading serverless also, incase it was fixed, but nae.

  package: 
   { individually: undefined,
     path: undefined,
     artifact: undefined,

@dschep
Copy link
Contributor Author

dschep commented Apr 25, 2018

You are correct that package.artifact doesn't get set, but the packageFunction hook is passed the function object which should have an artifact set on it. https://github.com/UnitedIncome/serverless-python-requirements/pull/180/files#diff-168726dbe96b3ce427e7fedce31bb0bcR136

@AndrewFarley
Copy link
Contributor

AndrewFarley commented Apr 25, 2018

@dschep I fixed the problem with the following at the end of my inject.js file... this seems to fix all the problems. This inline if was in the if this.serverless.service.package.individually stanza above just copied to the else stanza worked perfectly, seen below.

....
    return injectRequirements(
      path.join('.serverless', 'requirements'),
      this.serverless.service.package.artifact ? this.serverless.service.package.artifact : funcArtifact,
      this.options
    );

@dschep
Copy link
Contributor Author

dschep commented Apr 25, 2018

Huh. Thought i'd done that for some reason. Added it. Thanks! 👍

@AndrewFarley
Copy link
Contributor

Super excited to get single function deploys working again! :) I had a huge grin on my face just now seeing it work again, will (re)accelerate developer velocity over here. Cheers!

lib/inject.js Outdated
@@ -117,7 +117,7 @@ function injectAllRequirements(funcArtifact) {
} else {
return injectRequirements(
path.join('.serverless', 'requirements'),
this.serverless.service.package.artifact,
this.serverless.service.package.artifact || funcArtifact
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting a syntax error. I think you're missing the , at end of line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. yes! (and that's probably why depcheck didn't think we use glob-all too)

@AndrewFarley
Copy link
Contributor

Well, this confirmed works for me in all my serverless stacks, mixed or not, individually or not, and does single function deploys again. So I'm ready/eager for a merge, but can we get a few more eyes on it just incase?

@dschep
Copy link
Contributor Author

dschep commented Apr 26, 2018

I'll go ahead and merge it (but not yet push to npm) and test it out on my personal projects tonight. Yeah, a known set of contributors/users who are willing to test features before release would be nice to have. I'll consider you as being on that list for now 😉

@dschep dschep merged commit 21f031b into master Apr 26, 2018
@dschep dschep deleted the issues-161-179 branch April 26, 2018 12:52
@cgrimal
Copy link

cgrimal commented Apr 26, 2018

Hi guys, I was following the issue, especially after I updated the plugin before deploying an update of my Lambda function and it did not work!

I ended up pulling the branch I forked to implement the per function requirements in order to be able to deploy, but now that I have a bot more time, I pulled master, and I'm afraid I still have the Cannot set property 'artifact' of undefined error when deploying a single function.

I'm gonna try to have a look at the code and I'll keep you updated.

@cgrimal
Copy link

cgrimal commented Apr 26, 2018

The problem seems to be that I have 2 functions defined in my project, and when I try to deploy the first one, the whole process (requirements installation, etc.) is done for both function. I don't think this is a recent issue, but now, the artifact property is not defined for the functions other than the one I want to deploy, hence the error.

@AndrewFarley: you say it works for you, so I'm curious, do you have one function or multiple functions defined in your serverless.yml file? If you only have one, can you try adding another one and try again?

If I'm correct, one solution would be to check what function is being processed. In almost all functions, we do something like:

if this.serverless.service.package.individually:
    for each function:
       // do stuff

when it should be:

if this.serverless.service.package.individually:
    for each function:
        if not single function deploy or function is the one deployed:
           // do stuff

Does it make sense?

@dschep
Copy link
Contributor Author

dschep commented Apr 26, 2018

That makes sense @cgrimal! Feel free to make a PR if you have time before I do.

@cgrimal
Copy link

cgrimal commented Apr 26, 2018

I think I manage to have a "working" version, but the injection part was very long, and the vendors were not included. probably unrelated but not workable for me...

This is the end of the day in my timezone and I'll be on annual leave tomorrow night, so I'm afraid I'll have to leave it to you guys, sorry.

Here are the modifications I did in inject.js:

  • import lodash.keys instead of values
  • replace the loop on values(this.serverless.service.functions) to keys(this.serverless.service.functions)
  • add this filter .filter(f => f == this.serverless.variables.options.function)
  • update the previous filter to .filter(f => (this.serverless.service.functions[f].runtime || this.serverless.service.provider.runtime).match(/^oython.*/))
  • in the first map, get the func body with: var func = this.serverless.service.functions[f]; (f being the key)

So it is very basic, I just iterate over the keys instead of the values, as this is the key being passed as CLI argument to deploy a single version, that I get from this.serverless.variables.options.function.

The same should be done in other modules.

I hope it helps, really sorry to leave it like that. If there are still issues when I'm back in mid-May, I'll have a look!

Many thanks

@dschep
Copy link
Contributor Author

dschep commented Apr 26, 2018

No worries. Thanks for the notes. Enjoy your vacation!

@AndrewFarley
Copy link
Contributor

AndrewFarley commented Apr 26, 2018

Re: @cgrimal Most of my stacks have multiple functions, and I injected one of a non-python runtime for some brief testing and didn't run into any issues, with or without individually set. I'm sure I didn't try out every single usage configuration path I'm sure though. Probably need more tests to help cover/catch all these things that seem to not get caught currently. Thanks for giving it another look

@dschep
Copy link
Contributor Author

dschep commented Apr 26, 2018

I'm gonna try to add a second set of tests (deploy-tests.bats probably) but wont run them in CI since I don't want people to be able to deploy random crap to my AWS account by changing the test lambdas and making a PR. Test cases we need AFAICT:

  • basic python service
  • python service with individually & a non-python function
    • deploy
    • deploy -f py_func
    • deploy -f nodeFunc
  • node service with a python function with individually

Anyother things i shoudl consider?

(i'm even gonna also actually invoke the lambdas, which will prove that the packaged deps are really usable too!)

@AndrewFarley
Copy link
Contributor

AndrewFarley commented Apr 27, 2018

@dschep Great plan, I think that mostly covers it... I agree don't run those in CI, but definitely make them something you/we can run locally to check/guarantee(ish) that things that are generated are sane. Definitely make sure to try out the lambdas, make sure (of course) when you try the lambdas, the code you run should try using an included super simple pip module as well, to catch incase it doesn't zip deps. That should be the same kind of test used for when doing a full deploy, or a single func and/or individually packaged deploy.

@dschep dschep mentioned this pull request May 7, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants