在 AWS CloudFormation 模板中引用 !Ref DynamoDB 表名

Posted

技术标签:

【中文标题】在 AWS CloudFormation 模板中引用 !Ref DynamoDB 表名【英文标题】:Referencing !Ref DynamoDB table name in a AWS CloudFormation template 【发布时间】:2019-12-13 13:29:38 【问题描述】:

我正在尝试在本地测试传递我的 CloudFormation 模板文件中声明的 DynamoDB 表的表名。

从我阅读的所有文档中,我应该能够使用 !Ref 内在函数引用 DynamoDB 资源的 TableName 属性值。但是,当我在本地对此进行测试时,该属性是未定义的。

考虑以下示例:

Transform: 'AWS::Serverless-2016-10-31'
Resources:
  ServerlessFunction:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: nodejs10.x
      Handler: index.handler
      Environment: 
        Variables:
          TABLE_NAME: !Ref DynamoDBTable # <- returning undefined
      Events:
        GetCocktails:
          Type: Api
          Properties:
            Path: /
            Method: get
  DynamoDBTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: DynamoDBTableName
      AttributeDefinitions:
        - AttributeName: ID
          AttributeType: S
      KeySchema:
        - AttributeName: ID
          KeyType: HASH
      ProvisionedThroughput: 
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1

我希望 TABLE_NAME 环境变量为 DynamoDBTableName 但它返回未定义。如何让模板按预期工作?

【问题讨论】:

我刚刚修复了您的问题以引用 CloudFormation,因为您的问题与 CloudFormation 相关,而不是 SAM。也就是说,经过简短的查看后,它应该可以按您的预期工作。您能否在尝试访问环境变量的地方添加您的 AWS Lambda 函数的代码? 我正在寻找如何做同样的事情并在这里找到了您的问题。你所做的事情对我有用。无论如何,谢谢你在这里问。 谁能提供 JSON 格式的 cloudformation 模板的答案/解决方案? 【参考方案1】:

正如其他人所说,AWS::DynamoDB::Table 公开的唯一属性是: ArnStreamArn(参见 AWS CloudFormation DynamoDB Documentation)。

提供了 DynamoDB 的 arns 的语法,您可以通过以下方式检索表名:

      Environment: 
        Variables:
          TABLE_NAME: !Select [1, !Split ['/', !GetAtt DynamoDBTable.Arn]] 

这将返回DynamoDBTableName

【讨论】:

您是正确的,公开的属性是 Arn 和 StreamArn。即调用 !GetAttr 但调用 !Ref 返回表名 "对于逻辑 ID 为 myDynamoDBTable 的资源,Ref 将返回 DynamoDB 表名。" 即Ref returns the name of the table【参考方案2】:

!Ref 通过“逻辑名称”返回资源名称,应该适用于您的情况。但是资源(您的表)在您引用它之前应该存在,因此您有 2 个选项:

在模板的前面声明你的表资源(在你引用它之前)

在你的 lambda 上使用 DependsOn 属性

ServerlessFunction:
    Type: AWS::Serverless::Function
    DependsOn: DynamoDBTable

至于使用Fn::GetAtt

基于AWS Documentation,当您创建AWS::DynamoDB::Table 类型的资源时,Fn::GetAtt 只有两个属性可用:

Arn StreamArn

这意味着在当前版本的 CloudFormation 中,无法使用 Fn::GetAtt 获取 DynamoDB 表的 TableName 属性。

【讨论】:

仅供参考:DependsOn 属性是隐式使用 !Ref (docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/…)【参考方案3】:

我也遇到了同样的问题,您似乎无法访问 TableName。

我正在做的解决方法是使用相同的表名调用 tamplate.yml 中的资源...

在template.yml中:

Globals:
  Function:
    Runtime: nodejs12.x
    ...
    Environment:
      Variables:
        DYNAMODB_TABLE: !Ref MyDynamoTable
MyDynamoTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: MyDynamoTable
      AttributeDefinitions:
        - AttributeName: PK
          AttributeType: S
        - AttributeName: SK
          AttributeType: S

然后,在我的 .js 组件中:

const tableName = process.env.DYNAMODB_TABLE;

我希望他们能尽快解决这个问题......这种方式并不理想。 干杯!

【讨论】:

【参考方案4】:

您能否通过查看控制台中的 lambda 函数并验证环境变量不低于应有的位置来验证这不起作用?

【讨论】:

【参考方案5】:

即使 !Ref 确实返回了资源的逻辑 ID,在本例中为 DyanmoDB 表名,您需要在引用它之前确保该资源存在。

据我在您的代码中看到,函数创建不依赖于首先创建的 Dynamo 表

ServerlessFunction:
Type: AWS::Serverless::Function
Properties:
  Runtime: nodejs10.x
  Handler: index.handler
  Environment: 
    Variables:
      TABLE_NAME: !Ref DynamoDBTable 
  Events:
    GetCocktails:
      Type: Api
      Properties:
        Path: /
        Method: get

在这种情况下,CFN 将从上到下创建资源,这意味着 lambda 函数将在 DyanoDb 表之前创建,导致 !Ref 未定义,因为该表尚不存在。您可以通过添加对 lambda 资源的依赖项来解决此问题,如下所示:

ServerlessFunction:
DependsOn: DyanamoDBTable # <- will not be created before the dyanmoDB table
Type: AWS::Serverless::Function
Properties:
  Runtime: nodejs10.x
  Handler: index.handler
  Environment: 
    Variables:
      TABLE_NAME: !Ref DynamoDBTable
  Events:
    GetCocktails:
      Type: Api
      Properties:
        Path: /
        Method: get

这将确保无论如何,首先创建您的表,然后不会取消定义资源的 !Ref,因为该表已经存在并且可以被引用

【讨论】:

可以参考这里资源的返回值docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/…【参考方案6】:

!Ref DynamoDBTable 从您的资源中返回 ARN,因此您会得到如下参考响应:

arn:aws:dynamodb:us-east-1:123456789012:table/testddbstack-myDynamoDBTable-012A1SL7SMP5Q/stream/2015-11-30T20:10:00.000

相反,您只需要提供名称DynamoDBTableName,因此我的建议是使用!GetAtt CloudFormation 内部函数并获取名称: !GetAtt DynamoDBTable.TableName

【讨论】:

我收到An error occurred (ValidationError) when calling the CreateChangeSet operation: Template error: resource myDynamoDbTable does not support attribute type TableName in Fn::GetAtt 实际上,AWS DynamoDB 资源的 !Ref 函数返回的是表名,而不是 ARN。尝试使用!GetAtt 时,我遇到了与上述评论相同的错误。我没有使用环境变量,但我可以使用!Ref 获取我的 DynamoDB 资源的表名。

以上是关于在 AWS CloudFormation 模板中引用 !Ref DynamoDB 表名的主要内容,如果未能解决你的问题,请参考以下文章

AWS Inspector 的 AWS CloudFormation 模板能否添加 SNS 主题

如何使用 aws cloudformation 模板在 aws cognito 用户池中设置所需属性?

如何在 AWS CloudFormation YAML 模板中转义策略变量

aws cloudformation 模板 sns sqs

AWS::ElasticBeanstalk::ConfigurationTemplate 的 AWS CloudFormation 模板失败

迭代模板中的 AWS cloudformation 资源数组