Skip to content

Add imports and exports functionality (Cross-Stack-References)#3475

Closed
pmuens wants to merge 2 commits into
masterfrom
add-imports-and-exports-functionality
Closed

Add imports and exports functionality (Cross-Stack-References)#3475
pmuens wants to merge 2 commits into
masterfrom
add-imports-and-exports-functionality

Conversation

@pmuens

@pmuens pmuens commented Apr 14, 2017

Copy link
Copy Markdown
Contributor

What did you implement:

Closes #3442

This WIP PR implements the imports and exports support as described in #3442.

/cc @brianneisler @eahefnawy

How did you implement it:

Imports

Import values can be defined with the help of the imports keyword.

Those values are then translated into Serverless variables and can therefore be placed anywhere in the serverless.yml file.

The AwsCompileImports plugin checks for the populated variable in the serverless.yml file and replaces this value with the corresponding CloudFormation Fn::ImportValue statement. It's furthermore checked if the Serverless imports variable is imported beforehand so that a population is not happening if it's not explicitly imported.

Exports

Export values can be specified with the help of the exports config variable in the serverless.yml file

Those values are then compiled into corresponding CloudFormation Outputs by the AwsCompileExports plugin.

How can we verify it:

Here's a serverless.yml file which shows how this looks like:

service: service

provider:
  name: aws
  runtime: nodejs6.10

exports:
  writeKey: QWERTY1234

imports:
  users-dev: # the stack which exports this values
    - bucketName # the value which should be imported from that stack

functions:
  hello:
    handler: handler.hello

resources:
  Resources:
    Type: "AWS::S3::Bucket"
    Properties:
      BucketName: ${imports:users-dev.bucketName}

Just run serverless package and take a look in the generated CloudFormation output.

Todos:

  • Write tests
  • Write documentation
  • Fix linting errors
  • Make sure code coverage hasn't dropped
  • Provide verification config / commands / resources
  • Update the messages below

Is this ready for review?: NO
Is it a breaking change?: NO

@pmuens pmuens added this to the 1.12 milestone Apr 14, 2017
@pmuens
pmuens force-pushed the add-imports-and-exports-functionality branch 3 times, most recently from 7c40fed to d215865 Compare April 17, 2017 08:48
@pmuens
pmuens force-pushed the add-imports-and-exports-functionality branch from d215865 to a4f9c91 Compare April 17, 2017 08:48
Comment thread lib/classes/Variables.js
this.envRefSyntax = RegExp(/^env:/g);
this.optRefSyntax = RegExp(/^opt:/g);
this.selfRefSyntax = RegExp(/^self:/g);
this.importsRefSyntax = RegExp(/^imports:/g);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This source is not needed imo. Adds lots of technical debts. Lets just use "self"

@pmuens pmuens Apr 18, 2017

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately this is not possible (tried it yesterday).

The idea with this PR is that you define imports in your serverless.yml file. Those imports are then translated to Fn::ImportValue statements for AWS which are basically attached to the imports statement in the variable system.

The extension in the variable system only checks if the value is implicitly defined in the imports section so that users can't simply use the imports from the variable system if they are not defined in the service.imports configuration.

Using self here won't help since we're not populating anything.

Comment thread lib/classes/Variables.js
return valueToPopulate;
}

getValueFromImports(variableString) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We won't need this method at all

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This method checks if the user who want's to use imports via the variable system has explicitly defined what he want's to use in the service.imports config.


compileImports() {
const that = this; // save this because of the upcoming scope switch
traverse(this.serverless.service).forEach(function (propertyParam) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why do we use traverse here instead of following the same style we're using with exports?

-> exports = this.serverless.service.exports?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We traverse here since the usage for an import (via the variable system) can be everywhere in the serverless.yml file.

You can see an example in the service I posted for the verification (#3475 (comment)).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

gotcha. If we're gonna use the built in variable system via self we won't need that I think

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sounds good!

if (typeof propertyParam === 'string' && propertyParam.match(/imports:.+/)) {
const removedPrefix = propertyParam.split(':')[1];
const parts = removedPrefix.split('.');
const stack = parts[0];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not sure if this would work. Remember that the stack name is not just the service name, but it also includes the stage. This pegs the question whether the user should reference a service (in which case he'd have to choose a stage) or the full stack name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is the part the user defines in the imports config section.

So he needs to explicitly append the stage to the stack name:

imports:
  my-service-dev:
    - foo
    - bar

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ah ok so he provides the stack name not service name. Gotcha! 👍

@pmuens pmuens Apr 19, 2017

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yep, exactly! 👍

This way it's possible to e.g. from different stages. Don't know if that's a commonly used feature though...

@eahefnawy eahefnawy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I know this is WIP, but just added some comments that might be helpful. 😊

Thanks for jumping into this @pmuens 👍

@eahefnawy

Copy link
Copy Markdown
Contributor

We're now implementing this feature in PR #3575

Closing...

@eahefnawy eahefnawy closed this May 9, 2017
@pmuens
pmuens deleted the add-imports-and-exports-functionality branch May 9, 2017 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants