Using Ref as the first argument in Fn::Sub intrins

2019-04-08 04:52发布

问题:

I experience quite strange issues when compiling the template, where I reference a string parameter in Fn::Sub, while the docs do explicitly say that one can use Ref function inside of Fn::Sub. Here is a piece of template:

"Resources": {
    "LaunchConfiguration": {
      "Type" : "AWS::AutoScaling::LaunchConfiguration",
      "Properties" : {
        "UserData": { "Fn::Base64": { "Fn::Sub": { "Ref": "UserDataParam" } } },

And here is an error I get:

Template error: One or more Fn::Sub intrinsic functions don't specify expected arguments. Specify a string as first argument, and an optional second argument to specify a mapping of values to replace in the string

When I use full notation: { "Fn::Sub": [ { "Ref": "UserDataParam" }, {} ] }, I get exactly the same error. Has anybody had the same issue? And is it possible to avoid it while still using the parameter?

回答1:

You cannot directly use a Ref within a Fn::Sub function call. To achieve a value mapping, you first have to assign the Ref value into a local variable und use that one within the Fn::Sub string.

"UserData": {
  "Fn::Base64": {
    "Fn::Sub": [
      "${variable}",
      {
        "variable": {
          "Ref": "myS3Bucket"
        }
      }]
  }
}


回答2:

Alternatively it's possible to substitute directly without using a separate variable:

"UserData": {
  "Fn::Base64": {
    "Fn::Sub": "${myS3Bucket}"
  }
}

The key is to use Fn::Sub without the usual square brackets as explained at https://forums.aws.amazon.com/message.jspa?messageID=745085#745085



回答3:

You are misreading the docs. While the docs do say you can use the Ref function, it is only in the second (optional) parameter (the key-value map) where you can do that.

The example given in the docs is:

{"Fn::Sub": ["www.${Domain}", {"Domain": {"Ref": "RootDomainName"}}]}

If, however, you need to substitute into the first parameter, you must use the dollar notation.

To achieve what you appear to want, you should rewrite your code as:

{"Fn::Sub": "${UserDataParam}"}

Or in context:

"UserData": {"Fn::Base64": {"Fn::Sub": "${UserDataParam}"}}