Search code examples
amazon-web-servicesaws-cloudformationamazon-efs

Ref not getting resolved in user data in cloud formation


I am creating an EFS volume in cloud formation and trying to reference that in the User data of launch template.

I have tried multiple syntaxes of using Ref in CF but getting the same error everytime. I actually want to do different stuff with EFS but posting sample code which is also not working

  ClusterFileSystem:
    Type: AWS::EFS::FileSystem
    Properties:
      Encrypted: true

ClusterLaunchTemplate:
  Type: AWS::EC2::LaunchTemplate
  DependsOn: ClusterFileSystem
  Properties:
    LaunchTemplateName: !Sub ${AWS::StackName}
    LaunchTemplateData:
      ImageId: !Ref 'AMIId'
      SecurityGroupIds: [!GetAtt 'ClusterSecurityGroup.GroupId']
      InstanceType: !Ref 'InstanceType'
      BlockDeviceMappings:
      - DeviceName: "/dev/xvda"
        Ebs:
          VolumeSize: "40"
          VolumeType: "gp2"
          Encrypted: true
      - DeviceName: "/dev/xvdcz"
        Ebs:
          VolumeSize: "22"
          VolumeType: "gp2"
          Encrypted: true
      IamInstanceProfile:
        Name: 'ECSHostInstanceProfile'
      Monitoring:
        Enabled: true
      KeyName: !Ref 'Key'
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash -xe

          function setup-efs () {

            {
              mkdir -p /ecs-resources/${AWS::StackName}/environment
              EFS_FILE_SYSTEM_ID= !Ref ClusterFileSystem
              echo ${EFS_FILE_SYSTEM_ID} >> /tmp/xyz.txt
            }

This is the error am getting -

Template format error: Unresolved resource dependencies [EFS_FILE_SYSTEM_ID] in the Resources block of the template An error occurred (ValidationError) when calling the UpdateStack operation: Template format error: Unresolved resource dependencies [EFS_FILE_SYSTEM_ID] in the Resources block of the template - "


Solution

  • You don't need to use !Ref inside a !Sub, to get the same behaviour you can just reference the logical ID inside ${}.

    Additionally, you need to escape the ${EFS_FILE_SYSTEM_ID} since you want to print it literally instead of have !Sub parse it.

    UserData:
      Fn::Base64: !Sub |
        #!/bin/bash -xe
    
        function setup-efs () {
    
          {
            mkdir -p /ecs-resources/${AWS::StackName}/environment
            EFS_FILE_SYSTEM_ID= ${ClusterFileSystem}
            echo ${!EFS_FILE_SYSTEM_ID} >> /tmp/xyz.txt
          }
    

    Notice the reference to ${ClusterFileSystem} and the ! inside the curly braces for EFS_FILE_SYSTEM_ID.

    If you specify template parameter names or resource logical IDs, such as ${InstanceTypeParameter}, AWS CloudFormation returns the same values as if you used the Ref intrinsic function. If you specify resource attributes, such as ${MyInstance.PublicIp}, AWS CloudFormation returns the same values as if you used the Fn::GetAtt intrinsic function.

    And

    To write a dollar sign and curly braces (${}) literally, add an exclamation point (!) after the open curly brace, such as ${!Literal}. AWS CloudFormation resolves this text as ${Literal}.

    https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html