arabold / serverless-export-env

Serverless plugin to export environment variables into a .env file
MIT License
102 stars 34 forks source link

where do you put a variable that may cause a !Ref loop #34

Closed MorCohenAres closed 3 years ago

MorCohenAres commented 3 years ago

Hi,

I think version 2.0 introduces a new bug.

It happens when you add an environment variable to a lambda function that is a reference to a circular structure.

For example, consider the following serverless.yml:

CognitoUserPool:
      Type: AWS::Cognito::UserPool
      ...
      Properties:
        LambdaConfig:
          # A function to run when a user complete his registration
          PostConfirmation: !GetAtt ConfirmUserLambdaFunction.Arn 

functions:
  confirmUser:
    ...
    environment:
      #  This variable can come from either function-level or global-level vars, and it causes a reference loop
      COGNITO_USER_POOL: !Ref CognitoUserPool

With this yml, when you run sls deploy, the following error occurs:

Circular dependency between resources: [Function, ...]

In version 1 I would simply put that variable inside the Output section. The alternative in version 2 is to put it on the global provider.environment section, which is not possible in this case since it causes the variable to be copied into all lambda functions (and thus causing the described problem)

One possible workaround is to create some "mock" function that is not a dependency of anything, and put the problematic variables there, then use export-env --all to collect this variable.

arabold commented 3 years ago

@MorFixAres , thanks for reporting this. Indeed, it looks like this will introduce a circular dependency. I see two possibilities to break this here:

  1. You could define the Cognito user pool name manually in a Serverless variable and then use that name in your CognitoUserPool and confirmUser Lamba definition. Then you don't need the !Ref at all.
  2. Alternatively you can try to move the environment variable into your global environment settings but overwrite the value in all functions that should NOT have access to it. So basically you define it twice: Once globally with the correct !Ref value, and once again in the Lambd functions that should NOT receive it, where you set it to an empty value for example.

Hope that helps