16

i have a string the is formed from a number of variables which i use for many different things such as Tags and host names.

is there a way of creating a reusable string that i can just Ref though out the template?

any thoughts on this would be much appreciated. edit: An example would be passing in 2 parameters such as ProjectName and Environment joining them

"Fn::Join" : [ "-", [ {"Ref":"ProjectName"}, {"Ref":"Environment"} ] ]

and using the results in a number of places

Graeme
  • 660
  • 1
  • 5
  • 16
  • Are you talking about a parameter? http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/concept-parameters.html – Edwin Mar 03 '14 at 07:17
  • I think Transformations are what AWS provide for this. Sadly, they don't support YAML aliases yet. – jgomo3 Oct 12 '17 at 16:45

5 Answers5

7

Unfortunately my experiments are to agree with your conclusion Graeme. I have struggled with this for some time but not found a way of computing a String via Fn::Join and keeping it for later in the template.

Can I share with you a typical example?

As at 2014-09-18, the most sophisticated way of storing a string value for re-use in the Resources section would be via a (second-level) Mapping. Better still, I can pre-compute a Condition and determine whether to use the string or not. But unfortunately the storing of a string just does not work.

Here is an example stanza of such a Mapping …

    "LoadBalancerBucketMap": {
        "BucketName": {
            "string": {
                "Fn::Join": [
                    "-",
                    [
                        "mylb",
                        {
                            "Ref": "Environment"
                        },
                        "logs"
                    ]
                ]
            }
        }
    },

And here is an access expression to it in a Resource

                "S3BucketName": {
                    "Fn::FindInMap": [
                        "LoadBalancerBucketMap",
                        "BucketName",
                        "string"
                    }

In this example, Environment is a literal string Parameter with a convenient default. So that is a very clear example of creating and re-using a string. But here is what the CloudFormation processor says …

Template validation error: Template format error: Every Mappings attribute must be a String or a List.

So I share your frustration that there does not seem to be a way in a template to provide the effect of a temporary string variable.

… So far as I can see. But the answer you originally received said the opposite of this (although without an example).

So if anyone does have an example workaround, then please could they share?

johnz
  • 314
  • 3
  • 7
1

You can use params or mappings to store strings that you can use in your templates.

Drew Khoury
  • 4,569
  • 8
  • 26
  • 28
  • 2
    This only works for static strings. The OP specifically asked for computed strings, which doesn't seem to be possible at all. – Joe Apr 21 '16 at 20:31
0

If you haven't switched to CDK, you might consider switching to YAML. YAML has a concept of anchors (&) and aliases (*) that can be used anywhere in a document. The anchor must be defined before the alias is used. There's also a merge thing (<<: *<name>) that is almost always supported, including SAM or whatever I'm using, but not officially in the YAML spec.

This can make it easy to reuse whatever you'd like after it is first defined.

Resources:

  Hello:
    Type: AWS::Serverless::Function
    Properties: &FUNCTION_PROPERTIES      # This is the anchor
      Handler: index.handler
      Runtime: python3.6
      InlineCode: |
        def handler(event, context):
          print("Hello, world!")
      ReservedConcurrentExecutions: 30
      Layers:
        - Ref: MyLayer
      Tracing: Active
      Timeout: 120
      FileSystemConfigs:
        - Arn: !Ref MyEfsFileSystem
          LocalMountPath: /mnt/EFS
      Policies:
        - AWSLambdaExecute
        - Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - s3:GetObject
                - s3:GetObjectACL
              Resource: 'arn:aws:s3:::my-bucket/*'
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /path
            Method: get

  Goodbye:
    Type: AWS::Serverless::Function
    Properties:
      <<: *FUNCTION_PROPERTIES         # This is the alias
      InlineCode: |
        def handler(event, context):
          print("Goodbye, world!")

0

unfortunately i have found that it not possible to do what i was trying to achieve. it doesn't help but there it is.

Graeme
  • 660
  • 1
  • 5
  • 16
0

We actually make our CloudFormation stack name exactly {ProjectName}-{Environment} during aws cloudformation deploy. Have you considered this naming convention for your stack name?

Afterwards, you can just reference it as { "Fn:Sub": "${AWS::StackName}" }.

Ryan McGeary
  • 151
  • 1
  • 3