Skip to content
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

LanguageExtensions and Serverless-2016-10-31 conflicts - Support Intrinsic Function in DependsOn #109

Open
GavinZZ opened this issue Jan 16, 2023 · 8 comments

Comments

@GavinZZ
Copy link

GavinZZ commented Jan 16, 2023

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Tell us about the bug

AWSTemplateFormatVersion: "2010-09-09"
Transform:
  - AWS::LanguageExtensions
  - AWS::Serverless-2016-10-31
Parameters:
  paramEnvironment:
    Type: String
    Description: Which environment do you want to deploy to? (local,dev,stage, or prod)
    AllowedValues:
      - local
      - dev
      - stage
      - prod
    Default: local
Resources:
  resApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      OpenApiVersion: 3.0.1
      StageName: !Ref paramEnvironment
  resUsagePlan:
    Type: AWS::ApiGateway::UsagePlan
    DependsOn: resApiGatewayStage
    Properties:
      Description: Unlimited usage plan
      ApiStages:
        - ApiId: !Ref resApiGateway
          Stage: !Ref paramEnvironment

It appears that if AWS::LanguageExtensions is removed, paramEnvironment is treated as an intrinsic function, then the AWS::ApiGateway::Stage resource gets correct generated with the name resApiGatewayStage.
However, if we add AWS::LanguageExtensions, paramEnvironment is a fixed value after AWS::LanguageExtensions transform, then the resource name for ApiGateway Stage becomes resApiGatewaylocalStage.
Code for the above logic can be found here

However, if there is another resource say resUsagePlan that depends on the generated resource AWS::ApiGateway::Stage, this would be a deadlock for the customer because they don't know the exact generated name (depending on paramEnvironment), and AWS::LanguageExtensions doesn't allow intrinsics function in DependsOn.

Additional context

I do NOT think it's a bug from either SAM Transform or AWS::LanguageExtensions transform itself. However, when they both exists in a template like described above, customers can only resolve this issue by using intrinsic function in DependsOn, which is not supported by LanguageExtensions

@GavinZZ
Copy link
Author

GavinZZ commented Jan 16, 2023

This issue is also reported in SAM repo, however, there is no way we can resolve this without making a backward incompatible change. The only possible workaround is to have AWS::LanguageExtensions to support intrinsic function in DependsOn
Link to the same issue in SAM Repo aws/serverless-application-model#2778

@MalikAtalla-AWS
Copy link
Contributor

Thanks for raising this issue @GavinZZ. We'll triage it and will post updates here.

@MalikAtalla-AWS
Copy link
Contributor

So, just want to confirm that I'm able to reproduce the problem. When LanguageExtensions is used then the template is passed to SAM with StageName: "local". When LanguageExtensions is not used then the template is passed with StageName: !Ref paramEnvironment. And as you point out, SAM treats these two cases differently.

I want to make sure I understand your suggestion regarding the intrinsic function @GavinZZ. Are you suggesting something like this?

DependsOn: !Join
  - ''
  - - 'resApiGateway'
    - !Ref paramEnvironment
    - 'Stage'

@GavinZZ
Copy link
Author

GavinZZ commented Jan 18, 2023

Thanks for help investigating it. I'm suggesting exactly like you mentioned.

@MalikAtalla-AWS
Copy link
Contributor

Just to update the status here. Thanks @GavinZZ for the suggestion. What you propose is more of a feature than a bugfix, but I also couldn't think of a simpler way to address the issue. We will discuss internally if this is a feature we want to build and if so if there is dev capacity to build it.

@MaherAzzabi
Copy link

MaherAzzabi commented Feb 16, 2024

I am facing this same issue, in my template I am crating dynamically some Alarms that are attached to a CompositeAlarm,
I want to add a dependsOn section in my CompositeAlarm to mention the logicalIds of my Alarms but since the alarms are created dynamically I am not able to use !Sub or !Join or the %d to reference them.

For the Alarm creation I am using a Count to loop throw my ressources and create an alarm for each one:

Transform:
  - Count
...
Resources:
  Alarm:
    Count: 2
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName:
        !Join
          - ""
          - - !Select [ 0, !Ref MyList ]
            - "-my-log-alarm"
...

  CompositeAlarm:
    Count: 2
    Type: AWS::CloudWatch::CompositeAlarm

I want to add a DependsOn section like this, but it's not working:

    DependsOn:
      - !Join
          - ""
          - - !Select [ 0, !Ref MyList ]
            - "-my-log-alarm"

When I check the cloudFormation ressources, I saw that the alarms are created with logical Ids : Alarm1, Alarm2 ...
So when I switch the Depends on section like bellow, it works but It's not very clean as a solution since I am giving the logical Ids list manually, for same cases I have many alarms (a) for many ressources (r) then I have to add a x r lines

    DependsOn:
      - Alarm1
      - Alarm2

is there any clean solution for this please?

@GavinZZ
Copy link
Author

GavinZZ commented Jul 31, 2024

@MalikAtalla-AWS Any update on this feature? I've a number of reports that customers are stuck due to this conflict.

@BigButovskyi
Copy link

I’ve found a workaround for cases where one resource depends on another. You can split the dependent resource into a separate stack, and then deploy the stacks sequentially to ensure the proper order
Something like this should work.

Before

#Stack 1
  MyApi:
    Type: AWS::Serverless::Api
...
  ApiUsagePlan:
    Type: AWS::ApiGateway::UsagePlan
    DependsOn: MyApiStage
    Properties:
      ApiStages:
        - ApiId: !Ref MyApi
          Stage: "PROD"

After:

#Stack 1
  MyApi:
    Type: AWS::Serverless::Api

Outputs:
  MyApiId:
    Value:
      Ref: MyApi
    Export:
      Name: MyApiId

#Stack 2
  MyUsagePlan:
    Type: AWS::ApiGateway::UsagePlan
    Properties:
      ApiStages:
        - ApiId: !ImportValue MyApiId
          Stage: "PROD"

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

No branches or pull requests

4 participants