Invoke Local: Automatically add environment variables from yaml file#7147
Invoke Local: Automatically add environment variables from yaml file#7147nkeating-mutualofenumclaw wants to merge 53 commits into
Conversation
…rless.yml file to the invoke environment
There was a problem hiding this comment.
Hey @nkeating-mutualofenumclaw thanks for working on this! 👍
I just tested the current master with the attached serverless.yml and handler.js file and couldn't reproduce the problem. I ran invoke local with and without the --docker flag.
What runtime are you using? Could you paste the serverless.yml file you used when you ran into the problem?
Thanks in advance!
service: test-${self:custom.idx}
provider:
name: aws
runtime: nodejs10.x
versionFunctions: false
region: eu-central-1
stage: dev
environment:
PROVIDER: ${self:provider.name}
REGION: ${self:provider.region}
custom:
idx: 0
functions:
hello:
handler: functions/handler.handler
environment:
HANDLER: ${self:functions.hello.handler}
IDX: ${self:custom.idx}'use strict';
module.exports.handler = async event => {
console.log(process.env);
return {
headers: {
'Access-Control-Allow-Origin': '*', // Required for CORS support to work
'Access-Control-Allow-Credentials': true, // Required for cookies, authorization headers with HTTPS
},
statusCode: 200,
body: JSON.stringify(
{
message: 'Hello World!',
input: event,
},
null,
2
),
};
};|
Our serverless files we use get pretty complex which is why we thought the setting environment variables weren't working. Your example works without the modifications up until you start referencing AWS resources either through Ref, GetAtt or ImportValue. Looking at the existing serverless framework I think I found where the environment variables are currently being set. "lib/plugins/aws/invokeLocal/index.js". I'm thinking that I should remove that code I sent, and instead add an update to the previously mentioned file to interrogate the existing cloud formation deployment if it exists and translate those values. Modified Example: provider: environment: custom: functions: resources: Issue with output: |
|
I've reverted the original modifications and made changes to get referenced and imported resources for SNS, SQS, DynamoDB, Lambda and ImportValue. Here's the test yml I am using. To test import you will need to comment the reference to the export in the environment variables, deploy, then un-comment. Typically ImportValue would be used to get values from other cloudformation stacks. service: philipp-test-${self:custom.idx} provider: environment: custom: functions: hello2: resources: Outputs: |
medikoo
left a comment
There was a problem hiding this comment.
@nkeating-mutualofenumclaw Great thanks for this effort. If I read correctly, this looks as an attempt to solve: #7087
Still as I investigated the problem, without good AWS documentation there's no way to provide a reliable resource object to string resolution, and probably best solution (to unify resolution for every case for which it happens) is to reject resource object to string resolution in any case. I elaborated a bit more on that here: #7087 (comment)
Solution proposed here looks very use case specific (e.g. Ref or Fn::GetAtt instructions are blindly assumed to reference dynamo table). I don't think it can work well in generic framework logic, it's likely to fail for many other cases.
|
Hi Mariusz, That statement isn't quite accurate. Due to the way AWS operates as a consordium of individual teams, there isn't a single definition of Ref vs GetAtt. At the same time it is well documented what should be returned for each. The apis for each also have quite a bit of variation to them, making it hard to make a single function perform the value retrieval operation. This is why in the framework the conversion is broken down per service rather than trying to consolidate it all into a single function. Reference Documentation: The "lib/plugins/aws/invokeLocal/resolvers/index.js" file creates a registration process per handler as can be seen on lines 4 - 10. This is then used if a "Ref", "GetAtt" or "ImportValue" is used in the serverless yaml for the environment variables. As the values are retrieved they are cached in the "./.serverless" directory, which during a deployment will get removed as the cache might be invalid after the deployment. While there are more services than just the 5 I implemented, these 5 are the most commonly used with serverless AWS implementations. For any project which is significant, the ability to leverage references rather than hard coded values becomes critical, and there for local debugging without this with serverless framework without this capability is useless. With respect, as this is a primitive capability of AWS in the same way cloudformation is, this should be a framework level component as your user base shouldn't need to add a custom plugin just to be able to debug their basic stack functions. |
|
@nkeating-mutualofenumclaw great thanks for further clarifications. Indeed I was mislead by AWS support, I contacted them back on that, and they've responded:
In light of that, indeed it makes sense to implement resolution for popular cases, and eventually add resoulution for others on the go, whenever demand appears. Let me review the PR |
medikoo
left a comment
There was a problem hiding this comment.
@nkeating-mutualofenumclaw great thanks for looking into that!
Implementation direction looks very good. I've suggested some improvements, also please ensure proposed changes are free from lint errors and that code matches Prettier formatting.
Thank you!
| return action; | ||
| } | ||
| return func.Configuration.FunctionArn; | ||
| } |
There was a problem hiding this comment.
We should crash on any non Arn parameter.
There was a problem hiding this comment.
I'm wondering if we should crash, or just return the current value and let the deployment crash. Crashing debugging on a get attribute parameter seems like it would cause issues if GetAtt is extended in cloudformation. Not setting the value at least lets the user debug, but might not set the value correctly. Not exactly sure how to solve this one... maybe log that the attribute name is not supported?
There was a problem hiding this comment.
I would meaningfully crash, as otherwise we're clearly be providing an incomplete environment for local invocation
Fixing missing .serverless folder issue Fixing Import mapping to the same value
Handling situation where Fn::GetAtt is a string
…ing creates is more than it fixes
|
I've implemented the changes suggested. Let me know what you think |
Adding ecmaVersion 2017, to include async declarations.
medikoo
left a comment
There was a problem hiding this comment.
Thank you @nkeating-mutualofenumclaw !
Can you ensure CI passes, and that it's only feature related files that are committed in with this proposal (?) Currently I see some unrelated changes, in form of some IDE related files being added, and eslint config changes, which should not be introduced here.
|
I have on multiple times done what you had asked with more and new changes coming in the next review. I no longer have time to continue this back and forth, as I have other responsibilities. At this point the updates work and improve the serverless framework beyond what it is currently capable of doing. Your other customers are asking when this update will be available to them. If there are more changes you'd like to make or try, you should feel free to make them. If you'd like to recreate the whole resolution code base feel free to. |
|
@nkeating-mutualofenumclaw great thanks for this effort! It's a really worthwhile contribution, and I'm pretty sure many will appreciate it when it lands. We'll try to do our best to finish it whenever we have some free resources for that. If anyone wants to jump in, and finish this PR, it's very appreciated! |
|
What's happening with this change? |
|
@ionush we're looking for help, it's waiting for someone to take it over and finalize. |
|
Can the pull request from @medikoo be merged? |
|
Also interested in this change |
|
@PierrickI3 @corbfon we're looking for help in finalizing that pull request. Are you in for that? |
|
@medikoo In a project right now until the end of July and requires me to work in the evenings too. Not sure how much time I will be able to spare. |
|
@medikoo I could probably take a look later this week |
|
|
||
| const cachePath = path.join(cachedir('serverless'), 'invokeLocal'); | ||
|
|
||
| const envVarResolvers = { |
There was a problem hiding this comment.
@nkeating-mutualofenumclaw it would be great if you could add kinesis resolver as well.
|
Is anyone working on this PR? |
|
@herebebogans I don't think anyone is. Do you want to finish it? |
|
The problem with AWS Cloudformation intrinsic functions not being resolvable via environment variables when running locally (either via invoke local or serverless-offline) has come up many times and I've contributed to a few of those discussions. My thinking is that this is better left for plugins to solve otherwise the invokeLocal resolver module being created in this PR will need to be continually be updated as AWS update Cloudformation with new services. Theres a few plugins that already deal with this issue - though they have some limitations. The author of this PR has There is also. Perhaps the documentation for |
We should probably ensure unified behavior, and crash if we find that it can't be meet, so:
|
|
I'm guessing you raised this PR as it was difficult to implement this in a plugin? Like to get your input as you've put in a lot of work on it. |
@herebebogans My opinion on this is that it's serverless itself should include these env variables, not a plugin. The ultimate goal is that invokeLocal should behave as close to cloud execution as possible. This means if a lambda function in AWS gets a variable, it should get the same variable locally. |
I can understand how the surprise of Supporting the most commonly used resources ie .. S3, Dynamo , SQS etc as is being done in this PR would definitely help , however for this feature to be complete you would need to support all Cloudformation Resources which is a large initial and continous ongoing effort. In addition do you draw the line only supporting the common cloudformation return types ie !Ref, !GetAtt , !ImportValue etc, or would this resolver need to handle all CF intrinsic functions? eg something like
There's a larger issue already in serverless with CF intrinsic functions - they are supported and implemented differently across serverless. For example I can use !ImportValue in a sqs event definition but not in a kinesis event definition or for the provider.deployment bucket property .. Why? I think adding more of this only adds to the problem? |
|
Eventually all the scenarios should be covered. The problem is without a base of support, even around referenced variables, the framework itself starts becoming less useful for development purposes. This becomes even more stark when its the Solution Architect that chooses and typically writes the serverless file, and developers don't have the ability to do what other frameworks (like SAM) have baked in to their ability to debug. The FnIf example isn't that hard to implement as an additional feature, nor are other cloudformation functions. Trying to solve everything in one go though is setting this process up to be a long drawn out process, when a more iterative process would allow this feature to be added and improved on much more quickly. |
|
All good points, you've convinced me to finalise this PR .. |
|
@herebebogans, any luck? This would be really useful |
|
I had a look through the PR and started extending it to support more resources it but it's solely focused on supporting @medikoo can you think of a more general purpose way this can be solved in the framework to satisfy both. |
if you mean that resolution of env vars should be done in a way that serves both local invocation and eventual plugins. Then I think it can be achieved by secluding the resolution logic into What do you think? |
|
@nkeating-mutualofenumclaw great thanks for the effort! I'm going to close this as this was partially addressed by #8157 (added support for What's missing (and what was supposed to be covered with this PR) is support to resolve |
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #7147 +/- ##
==========================================
- Coverage 88.14% 87.08% -1.06%
==========================================
Files 236 243 +7
Lines 8640 8776 +136
==========================================
+ Hits 7616 7643 +27
- Misses 1024 1133 +109 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…rless.yml file to the invoke environment
What did you implement
Currently when invoking a function locally, the environment variables from the serverless.yml are not automatically included in the runtime environment for the function. This update puts the environment variables for the serverless.yml provider and functions as the default values, which can be overwritten by the command line parameters. This reduces the amount of work needed when dealing with hard coded environment variables in the serverless yml file.
Addresses #7087
How can we verify it
Run the tests, or:
Todos
N/A
Is this ready for review?: YES
Is it a breaking change?: NO