aws-cloudformation / cfn-language-discussion

Language discussions for CloudFormation template language
https://aws.amazon.com/cloudformation/
Apache License 2.0
142 stars 13 forks source link

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

Open GavinZZ opened 1 year ago

GavinZZ commented 1 year ago

Community Note

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 commented 1 year ago

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 https://github.com/aws/serverless-application-model/issues/2778

MalikAtalla-AWS commented 1 year ago

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

MalikAtalla-AWS commented 1 year ago

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 commented 1 year ago

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

MalikAtalla-AWS commented 1 year ago

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 commented 7 months ago

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 commented 2 months ago

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