前面简单的过了一遍模板的9大模块,这一节学习一下他的内置函数(Intrinsic function)。

官方文档链接 https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html

Fn::Base64

这个是返回一个字符串的base64格式,一般的使用场景是创建EC2 实例的时候配置 UserData使用的。注意Yaml格式2可以简写 Fn:: 为!,不要和其他语言里面的NOT操作符搞混了

JSON格式
{ "Fn::Base64" : valueToEncode }

YAML格式
*Fn::Base64: valueToEncode

YAML格式2
!Base64 valueToEncode

Fn::Cidr

这个是返回一个IP地址块

JSON格式
{ "Fn::Cidr" : [ipBlock, count, cidrBits]}

YAML格式
Fn::Cidr:

  • ipBlock
  • count
  • cidrBits

YAML格式2
!Cidr [ ipBlock, count, cidrBits ]

例子, 创建了一个192.168.0.0/24的地址快,然后在里面创建了6个子网掩码 为/27的CIDR块


{ "Fn::Cidr" : [ "192.168.0.0/24", "6", "5"] }

Fn::FindInMap

在一个两层的map里面返回对应的value,之前看过例子通过region来查找AMI ID

JSON格式
{ "Fn::FindInMap" : [ "MapName", "TopLevelKey", "SecondLevelKey"] }

YAML格式
Fn::FindInMap: [ MapName, TopLevelKey, SecondLevelKey ]

YAML格式2
!FindInMap [ MapName, TopLevelKey, SecondLevelKey ]

Fn::GetAtt

这个是通过指定resource来返回他对应的属性值

JSON格式
{ "Fn::GetAtt" : [ "logicalNameOfResource", "attributeName" ] }

FN::GetAZs

这个指定一个region,返回他的所有的AZ的列表

JSON格式
{ "Fn::GetAZs" : "region" }

另外,当用户获取他所在的Region的时候, 这个Region的信息本身就是一个全局变量,不需要用户去指定,所以我们可以通过下面两张方式都可以获取当前用户所在的region的AZ

{ "Fn::GetAZs" : "" }
{ "Fn::GetAZs" : { "Ref" : "AWS::Region" } }

再比如这个片段, 通过Fn::GetAZs获取整个AZ的列表了,再通过Fn::select来获取第一个索引的元素


"mySubnet" : {
  "Type" : "AWS::EC2::Subnet",
  "Properties" : {
    "VpcId" : { 
      "Ref" : "VPC"   
    },
    "CidrBlock" : "10.0.0.0/24",
    "AvailabilityZone" : {
      "Fn::Select" : [ 
        "0", 
        { 
          "Fn::GetAZs" : "" 
        } 
      ]
    }
  }
}

Fn::ImportValue

这个可以从其他stack的output结果里面导入

JSON语法
{ "Fn::ImportValue" : sharedValueToImport }

Fn::Join
这个类似字符串的拼接,通过自定义的分隔符进行连接,如果分隔符是空的字符串,那么这些字符就直接连接

JSON语法
{ "Fn::Join" : [ "delimiter", [ comma-delimited list of values ] ] }

例如,我想拼接出一个arn来

{
  "Fn::Join": [
    "", [
      "arn:",
      {
        "Ref": "Partition"
      },
      ":s3:::elasticbeanstalk-*-",
      {
        "Ref": "AWS::AccountId"
      }
    ]
  ]
}

Fn::Select

这个函数可以通过指定索引,返回一个列表里面的元素对象

JSON格式
{ "Fn::Select" : [ index, listOfObjects ] }

YAML格式
Fn::Select: [ index, listOfObjects ]
!Select [ index, listOfObjects ]

例子:

"Parameters" : {
  "DbSubnetIpBlocks": {
    "Description": "Comma-delimited list of three CIDR blocks",
    "Type": "CommaDelimitedList",
      "Default": "10.0.48.0/24, 10.0.112.0/24, 10.0.176.0/24"
  }
}

"Subnet0": {
  "Type": "AWS::EC2::Subnet",
    "Properties": {
      "VpcId": { "Ref": "VPC" },
      "CidrBlock": { "Fn::Select" : [ "0", {"Ref": "DbSubnetIpBlocks"} ] }
    }
}

Fn::Split

这个和join相反,是通过分隔符来分割字符串的

JSON语法
{ "Fn::Split" : [ "delimiter", "source string" ] }

YAML语法
Fn::Split: [ delimiter, source string ]
!Split [ delimiter, source string ]

例子,分割一条导入的子网记录,然后选择其中的第三个元素


{ "Fn::Select" : [ "2", { "Fn::Split": [",", {"Fn::ImportValue": "AccountSubnetIDs"}]}] }

Fn::Sub

替换字符串。他的一个常见的使用场景是在运行的时候,把实际的值传给我们自定义的变量

{ "Fn::Sub" : [ String, { Var1Name: Var1Value, Var2Name: Var2Value } ] }

如果仅仅是替换Paramter,Resource的名字,或者Resource的某个属性名称,直接用字符串替换就是了
{ "Fn::Sub" : String }

下面看几个例子

${domain}是一个我自定义的变量,然后通过Ref获取真实的域名进行替换

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

另外一个例子,通过全局变量和vpc的名字进行替换


{ "Fn::Sub": "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc/${vpc}" }

第三个例子,在userdata里面使用,通过替换来配置对应的bash命令,然后通过join拼成一个合法的bash文件,再转换成对应的base64格式

"UserData": { "Fn::Base64": { "Fn::Join": ["\n", [
  "#!/bin/bash -xe",
  "yum update -y aws-cfn-bootstrap",
  { "Fn::Sub": "/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfig --configsets wordpress_install --region ${AWS::Region}" },
  { "Fn::Sub": "/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerGroup --region ${AWS::Region}" }]]
}}

Fn::Transform

调用宏,这个后面会有详细例子

Fn::Ref

这个命令返回Parameter或者resoruce的值

JSON语法
{ "Ref" : "logicalName" }

YAML语法

Ref: logicalName
!Ref logicalName

例如:

"MyEIP" : {
   "Type" : "AWS::EC2::EIP",
   "Properties" : {
      "InstanceId" : { "Ref" : "MyEC2Instance" }
   }
}