cloudformation-cli icon indicating copy to clipboard operation
cloudformation-cli copied to clipboard

CF cannot preprocess the stack when a module parameter appears in the conditions block and using a !Ref or !GetAtt function

Open ecastillac opened this issue 1 year ago • 0 comments

Description

When using a CF module, if you use an intrincic function expression to assign the value of module parameter, and the template source of the module uses the parameter name in a condition, CF cannot preprocess the stack and exits with error

CloudFormation failed to preprocess the stack: 
  Template format error: 
    Unresolved dependencies [resSampleModule1resSourceQueue]. Cannot reference resources in the Conditions block of the template

Steps to reproduce

1. Create a module called Fujitsu::CF::SampleModule1::MODULE using the template module1.yml as fragment:

module1.yml
===========
AWSTemplateFormatVersion: 2010-09-09
Description: "Template to generate an example module with name Fujitsu::CF::SampleModule1::MODULE"

Parameters:

  parMaxReceiveCount:
    Description: Number of times a message is received by a consumer of the source queue before being moved to the dead-letter queue
    Type: Number
    Default: 3

Resources:

  resDeadLetterQueue: 
    Type: AWS::SQS::Queue
    
  resSourceQueue: 
    Type: AWS::SQS::Queue
    Properties: 
      RedrivePolicy: 
        deadLetterTargetArn: 
          Fn::GetAtt: 
            - "resDeadLetterQueue"
            - "Arn"
        maxReceiveCount: !Ref parMaxReceiveCount

Commands:

mkdir module1
cd module1
cfn init -t Fujitsu::CF::SampleModule1::MODULE -a MODULE --region eu-west-1
Replace fragmets/sample.json with module1.yml
cfn validate
cfn submit --region eu-west-1 --set-default

2. Create a module called Fujitsu::CF::SampleModule2::MODULE using the template module2.yml as fragment:

module2.yml
===========
AWSTemplateFormatVersion: 2010-09-09
Description: "Template to generate a samplemodule with name Fujitsu::CF::SampleModule2::MODULE"

Parameters:

  parBucketName:
    Description: S3 bucket name. If not specified, the S3 service assigns a name
    Type: String

  parVersioningConfiguration:
    Description: If versioning is enabled (Enabled) or disabled (Suspended)
    Type: String
    AllowedValues: ["Enabled","Suspended"]

Conditions:

  cndIsBucketNameSpecified: !Not
    - !Equals
      - ""
      - !Ref parBucketName

Resources:

  resS3Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: !If
        - cndIsBucketNameSpecified
        - !Sub ${parBucketName}-${AWS::Region}-${AWS::AccountId}
        - !Ref AWS::NoValue
      VersioningConfiguration:
        Status: !Ref parVersioningConfiguration

Outputs:

  outBucketName:
    Description: S3 bucket name
    Value: !Ref resS3Bucket

Commands:

mkdir module2
cd module2
cfn init -t Fujitsu::CF::SampleModule2::MODULE -a MODULE --region eu-west-1
Replace fragmets/sample.json with module2.yml
cfn validate
cfn submit --region eu-west-1 --set-default

3. Create a stack (called test in the image), from this template:

AWSTemplateFormatVersion: 2010-09-09
Description: "Sample parent template that uses Fujitsu::CF::SampleModule1::MODULE and Fujitsu::CF::SampleModule2::MODULE"

Parameters:

  parMaxReceiveCount:
    Description: Number of times a message is received by a consumer of the source queue before being moved to the dead-letter queue
    Type: Number
    Default: 3

Resources:

  resSampleModule1:
    Type: Fujitsu::CF::SampleModule1::MODULE
    Properties:
      parMaxReceiveCount: !Ref parMaxReceiveCount

  resSampleModule2:
    Type: Fujitsu::CF::SampleModule2::MODULE
    Properties:
      parBucketName: !GetAtt [resSampleModule1, resSourceQueue.QueueName]
      parVersioningConfiguration: "Suspended"

I will refer to this as the 'parent template'.

Expected behavior

The stack is created without errors.

Actual behavior

CF reports an error:

CloudFormation failed to preprocess the stack: 
  Template format error: 
    Unresolved dependencies [resSampleModule1resSourceQueue]. Cannot reference resources in the Conditions block of the template
bug-cf

The problem is the parent template uses an intrinsic function expression to assign value to a module parameter (parBucketName: !GetAtt [resSampleModule1, resSourceQueue.QueueName]), and the template fragment of the module uses the name of the assigned parameter (parBucketName) in a condition (cndIsBucketNameSpecified).

I think this is a bug because parBucketName in template fragment must be a name internal to the module.

ecastillac avatar Nov 11 '24 11:11 ecastillac