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

时间:2016-04-28 14:57:48

标签: amazon-web-services amazon-dynamodb amazon-cloudformation

我有一个现有的DynamoDB表,它被定义为CloudFormation堆栈的一部分。根据{{​​3}},GlobalSecondaryIndexes属性不需要替换。它甚至可以通过以下注意事项进行详细介绍。

  

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

以及以下......

  

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

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

CloudFormation cannot update a stack when a custom-named resource requires replacing. Rename mytablename and update the stack again.

由于我添加了一个使用新属性的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"
            }
          }
        }
      ]
    }
  }
}

以下是我要将其更新为:

{
  "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"
            }
          }
        }
      ]
    }
  }
}

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

5 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:5)

AWS支持对我的反应FWIW:

解决方法A

  1. 将表中的数据导出到s3
  2. 使用添加了gsi的新表名(tablename2)更新堆栈
    • 注意这会损失所有当前条目,所以一定要先备份到s3!
  3. 再次更新堆栈,返回使用dynamodb表中的tablename1
  4. 从s3导入数据这可以通过使用数据管道来缓解,请参阅
  5. 优点是,应用代码可以继续使用固定名称。但是,更新堆栈两次并导出/导入数据将需要一些工作来自动化自定义脚本。

    解决方法B

    1. 备份数据
    2. 让CloudFormation命名表
    3. 使用AWS开发工具包通过逻辑ID描述堆栈资源获取名称,并从输出中获取表名,使用AWS SDK检索表名。
    4. 虽然我认为这可以避免额外的堆栈更新(仍然认为需要导出/导入数据),但缺点是代码中的网络调用以获取表名。看到   * http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CloudFormation.html#describeStackResource-property

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

答案 2 :(得分:2)

备份DynamoDB中的所有数据,之后,如果您使用的是无服务器,请执行以下任一命令:

个人删除:

serverless remove

全局删除:

node ./node_modules/serverless/bin/serverless deploy -v

并通过运行:

再次部署它
serverless deploy

[Test]
public void action()
{
string excelFilePath = TestContext.Parameters["excelFilePath"];
string worksheetName = TestContext.Parameters["worksheetName"];
TestContext.WriteLine(excelFilePath);
TestContext.WriteLine(worksheetName);

答案 3 :(得分:2)

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

解决方案:删除cloudformation中的GSI,执行update-stack,然后重新添加GSI,再次执行update-stack,一切正常。

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

答案 4 :(得分:1)

我的情况是我想通过更改范围键来更新GSI。 -首先,您必须删除要更新的GSI,还要记住要删除由于删除了GSI而不再需要的所有AttributeDefinition,即索引名称等。通过CloudFormation上传模板以应用更改。 -然后将所需的属性和“更新的” GSI添加到模板中。