无法使用CloudFormation将GSI添加到DynamoDB表

Jar*_*eld 12 amazon-web-services aws-cloudformation amazon-dynamodb

我有一个现有的DynamoDB表,它被定义为CloudFormation堆栈的一部分.根据CFN AWS :: DynamoDB :: Table文档,GlobalSecondaryIndexes属性不需要替换.它甚至可以通过以下注意事项进行详细介绍.

您可以不间断地删除或添加一个全局二级索引.

以及以下......

如果更新表以包含新的全局二级索引,AWS CloudFormation将启动索引创建,然后继续进行堆栈更新.AWS CloudFormation不会等待索引完成创建,因为回填阶段可能需要很长时间,具体取决于表的大小.

但是,实际上当我尝试执行更新时,我收到以下错误消息:

CloudFormation cannot update a stack when a custom-named resource requires replacing. Rename mytablename and update the stack again.
Run Code Online (Sandbox Code Playgroud)

由于我正在添加一个使用新属性的GSI,因此我不得不修改AttributeDefinitions,它说它确实需要替换.但是,即使我尝试添加仅具有AttributeDefinitions中定义的现有属性的GSI,我仍然会收到相同的错误消息.

这是我原始CFN定义的片段:

{
  "myTable": {
    "Type": "AWS::DynamoDB::Table",
    "Properties": {
      "TableName": "mytablename",
      "AttributeDefinitions": [
        {
          "AttributeName": "entryId",
          "AttributeType": "S"
        },
        {
          "AttributeName": "entryName",
          "AttributeType": "S"
        },
        {
          "AttributeName": "appId",
          "AttributeType": "S"
        }
      ],
      "KeySchema": [
        {
          "KeyType": "HASH",
          "AttributeName": "entryId"
        },
        {
          "KeyType": "RANGE",
          "AttributeName": "entryName"
        }
      ],
      "ProvisionedThroughput": {
        "ReadCapacityUnits": {
          "Ref": "readThroughput"
        },
        "WriteCapacityUnits": {
          "Ref": "writeThroughput"
        }
      },
      "GlobalSecondaryIndexes": [
        {
            "IndexName": "appId-index",
          "KeySchema": [
            {
              "KeyType": "HASH",
              "AttributeName": "appId"
            }
          ],
          "Projection": {
            "ProjectionType": "KEYS_ONLY"
          },
          "ProvisionedThroughput": {
            "ReadCapacityUnits": {
              "Ref": "readThroughput"
            },
            "WriteCapacityUnits": {
              "Ref": "writeThroughput"
            }
          }
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

以下是我要将其更新为:

{
  "myTable": {
    "Type": "AWS::DynamoDB::Table",
    "Properties": {
      "TableName": "mytablename",
      "AttributeDefinitions": [
        {
          "AttributeName": "entryId",
          "AttributeType": "S"
        },
        {
          "AttributeName": "entryName",
          "AttributeType": "S"
        },
        {
          "AttributeName": "appId",
          "AttributeType": "S"
        },
        {
          "AttributeName": "userId",
          "AttributeType": "S"
        }
      ],
      "KeySchema": [
        {
          "KeyType": "HASH",
          "AttributeName": "entryId"
        },
        {
          "KeyType": "RANGE",
          "AttributeName": "entryName"
        }
      ],
      "ProvisionedThroughput": {
        "ReadCapacityUnits": {
          "Ref": "readThroughput"
        },
        "WriteCapacityUnits": {
          "Ref": "writeThroughput"
        }
      },
      "GlobalSecondaryIndexes": [
        {
            "IndexName": "appId-index",
          "KeySchema": [
            {
              "KeyType": "HASH",
              "AttributeName": "appId"
            }
          ],
          "Projection": {
            "ProjectionType": "KEYS_ONLY"
          },
          "ProvisionedThroughput": {
            "ReadCapacityUnits": {
              "Ref": "readThroughput"
            },
            "WriteCapacityUnits": {
              "Ref": "writeThroughput"
            }
          }
        },
        {
          "IndexName": "userId-index",
          "KeySchema": [
            {
              "KeyType": "HASH",
              "AttributeName": "userId"
            }
          ],
          "Projection": {
            "ProjectionType": "KEYS_ONLY"
          },
          "ProvisionedThroughput": {
            "ReadCapacityUnits": {
              "Ref": "readThroughput"
            },
            "WriteCapacityUnits": {
              "Ref": "writeThroughput"
            }
          }
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,就像我之前提到的那样,即使我没有在AttributeDefinitions中定义userId并在新的GSI定义中使用现有属性,它也不起作用并且失败并显示相同的错误消息.

小智 6

我今天遇到了同样的错误,得到了亚马逊技术支持的答案.问题是您提供了TableName字段.CloudFormation希望负责为您命名表格.显然,当您为它们提供自己的名称时,这是您更新替换表的错误(不确定为什么需要替换,但这就是文档所说的)

对我来说,这使得CloudFormation对于维护我的DynamoDB表完全没用.我必须构建配置,以便我的代码可以动态地告诉CloudFormation为我生成的随机表名称.

  • 亚马逊方面我不明白的是CloudFormation如何对Dynamo有用.当然我想选一张我名字的桌子......对我来说根本就没有意义. (3认同)

小智 6

这里的问题是怎么发生的?对我来说,在 dynamoDB 控制台中手动删除 GSI,然后通过 cloudformation 添加 GSI,update-stack 出现此错误。

解决方案:删除cloudformation中的GSI,执行update-stack,然后添加回GSI,再次执行update-stack,工作正常。

猜测 cloudformation 有自己的缓存,无法告诉您在控制台中手动完成的更改。


Thi*_*ien 5

AWS支持人员对我的答复FWIW:

解决方法A

  1. 将数据从表导出到s3
  2. 使用添加的gsi更新具有新表名(tablename2)的堆栈
    • 请注意,这会丢失所有当前条目,因此绝对要先备份到s3!
  3. 再次更新堆栈,回到在dynamodb表中使用tablename1
  4. 从s3导入数据这可以通过使用数据管道来简化,请参见

优点是,应用程序代码可以继续使用固定名称。但是更新堆栈两次和导出/导入数据将需要一些工作才能在自定义脚本中实现自动化。

解决方法B

  1. 备份数据
  2. 让CloudFormation为表命名
  3. 使用AWS开发工具包检索表名,方法是通过按逻辑ID描述堆栈资源来获取表名,然后从输出中获取表名。

尽管我认为这避免了额外的堆栈更新(仍然认为需要导出/导入数据),但缺点是需要通过网络调用代码来获取表名。请参阅* http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CloudFormation.html#describeStackResource-property

再次,这是一个已知问题,支持正在推动服务团队前进,因为我们知道这是一个非常普遍的用例和痛苦点。在进行生产测试之前,请在测试环境中尝试解决方法。