有没有办法从 CloudFormation 模板填充 Amazon DynamoDB table?
Is there a way to populate an Amazon DynamoDB table from a CloudFormation template?
我需要创建一个 DynamoDB table 是它在 CloudFormation 模板中作为参数传递的属性值之一:
DynamoDB table 应该如下所示:
PhoneNumber | OrderNumber
223546421 11545154
784578745 11547854
223458784 11547487
XXXXXXXXX 11578451
属性值“XXXXXXXXX”需要作为参数从 CloudFormation 模板传递,如果要创建 DynamoDB table 并使用上述信息填充。
这是构建 DynamoDB 的当前 CF 模板table:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"OrdersTable": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"TableName": "ClientOrders",
"AttributeDefinitions": [
{
"AttributeName": "PhoneNumber",
"AttributeType": "S"
},
{
"AttributeName": "OrderNumber",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "PhoneNumber",
"KeyType": "HASH"
},
{
"AttributeName": "OrderNumber",
"KeyType": "RANGE"
}
],
"TimeToLiveSpecification": {
"AttributeName": "ExpirationTime",
"Enabled": true
},
"ProvisionedThroughput": {
"ReadCapacityUnits": "10",
"WriteCapacityUnits": "5"
}
},
"DependsOn": [
"DynamoDBQueryPolicy"
]
},
"DynamoDBQueryPolicy": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "DynamoDBQueryPolicy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "dynamodb:Query",
"Resource": "*"
}
]
},
"Roles": [
{
"Ref": "OrdersTableQueryRole"
}
]
}
},
"OrdersTableQueryRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"dynamodb.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/"
}
}
}
}
我需要帮助来使用上面提到的值填充 table 以及如何将提到的属性值作为参数传递。
如有任何帮助,我们将不胜感激。
谢谢
没有办法通过 CloudFormation 将行添加到 DynamoDB table。 CloudFormation 是一种旨在 create/manage 基础架构而非数据的工具。我建议在一个单独的过程中这样做。例如,如果您通过 CodePipeline 进行部署,您可以拥有一个在 CloudFormation 创建后运行的 CodeBuild 作业。该代码几乎可以做任何您想做的事情。
可以选择创建一个 custom resource or a resource provider,但虽然有可能,但我认为这不在其预期目的之内。
我们需要 custom cloudformation 资源来将条目添加到 Dynamo Table。
来自文档:
With Lambda functions and custom resources, you can run custom code in
response to stack events (create, update, and delete).
This custom resource invokes a Lambda function and sends it the StackName property as input. The function uses this property to get outputs from the appropriate stack.
这是我为 1 个键创建的示例,需要一些小的改动:
我们需要两件事。
一,保存Lambda函数的堆栈。有了这个,当我们 add/remove/update 一个资源时,我们就没有在幕后调用这个 Lambda 的 cloudformation 资源。这通常一起进入单独的堆栈。
AWSTemplateFormatVersion: '2010-09-09'
Resources:
DynamoCfnLambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: '/'
Policies:
- PolicyName: dynamodbAccessRole
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:*
Resource: '*'
- Effect: Allow
Action:
- logs:*
Resource: '*'
CfnCrtUpdDltDynamodbDocumentLambda:
Type: AWS::Lambda::Function
Properties:
FunctionName: 'cfn-crt-upd-dlt-dynamodb-document'
Code:
ZipFile: >
const AWS = require("aws-sdk");
const response = require("./cfn-response");
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = function(event, context) {
console.log(JSON.stringify(event, null, 2));
var item = JSON.parse(event.ResourceProperties.DynamoItem);
var keyProperty = event.ResourceProperties.DynamoKeyProperty;
var tableName = event.ResourceProperties.DynamoTableName;
if (event.RequestType == "Create" || event.RequestType == "Update") {
console.log("item:", item);
var params = {
TableName: tableName,
Item: item
};
console.log("Creating or Updating Document");
docClient.put(params, function(err, data) {
if (err) {
console.log('error creating/updating document', err);
response.send(event, context, "FAILED", {}, tableName + '_' + item[keyProperty]);
} else {
response.send(event, context, "SUCCESS", {}, tableName + '_' + item[keyProperty]);
}
});
}
if (event.RequestType == "Delete") {
console.log("Deleting a Document");
var params = {
TableName: tableName,
Key: {
[keyProperty]: item[keyProperty]
}
};
docClient.delete(params, function(err, data) {
if (err) {
response.send(event, context, "FAILED", {});
} else {
response.send(event, context, "SUCCESS", {});
}
});
}
};
Handler: index.handler
Role: !GetAtt DynamoCfnLambdaRole.Arn
Runtime: nodejs10.x
Timeout: 60
其次,我们需要添加资源块 Custom::ThisCouldBeAnything
,ServiceToken
指向我们在上面创建的 Lambda Arn。每当我们
- 在任何 cloudformation 中添加一个新块,将使用 Create 调用 Lambda,这会在 Dynamo table.
中创建一个条目
- 从 Cloudformation 中删除块,Lambda 将使用 Delete 调用,从 Dynamo 中删除条目 Table。
- 更改资源块中的内容,例如更改 DynamoItem 中的内容,Lambda 将随更新一起调用。
对于要插入 Dynamo 的每条记录,我们都需要一个资源块。
Resources:
MyPhone223546421:
Type: Custom::CrtUpdDltDynamodbDocumentLambda
Properties:
ServiceToken: !GetAtt CfnCrtUpdDltDynamodbDocumentLambda.Arn
DynamoTableName: My-Table
DynamoKeyProperty: 'PhoneNumber'
DynamoItem: |
{
"PhoneNumber": "223546421",
"OrderNumber": "11545154",
"someKey": "someValue"
}
MyPhone784578745:
Type: Custom::CrtUpdDltDynamodbDocumentLambda
Properties:
ServiceToken: !GetAtt CfnCrtUpdDltDynamodbDocumentLambda.Arn
DynamoTableName: My-Table
DynamoKeyProperty: 'PhoneNumber'
DynamoItem: |
{
"PhoneNumber": "784578745",
"OrderNumber": "11547854",
"someKey": "someValue"
}
我需要创建一个 DynamoDB table 是它在 CloudFormation 模板中作为参数传递的属性值之一:
DynamoDB table 应该如下所示:
PhoneNumber | OrderNumber
223546421 11545154
784578745 11547854
223458784 11547487
XXXXXXXXX 11578451
属性值“XXXXXXXXX”需要作为参数从 CloudFormation 模板传递,如果要创建 DynamoDB table 并使用上述信息填充。
这是构建 DynamoDB 的当前 CF 模板table:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"OrdersTable": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"TableName": "ClientOrders",
"AttributeDefinitions": [
{
"AttributeName": "PhoneNumber",
"AttributeType": "S"
},
{
"AttributeName": "OrderNumber",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "PhoneNumber",
"KeyType": "HASH"
},
{
"AttributeName": "OrderNumber",
"KeyType": "RANGE"
}
],
"TimeToLiveSpecification": {
"AttributeName": "ExpirationTime",
"Enabled": true
},
"ProvisionedThroughput": {
"ReadCapacityUnits": "10",
"WriteCapacityUnits": "5"
}
},
"DependsOn": [
"DynamoDBQueryPolicy"
]
},
"DynamoDBQueryPolicy": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "DynamoDBQueryPolicy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "dynamodb:Query",
"Resource": "*"
}
]
},
"Roles": [
{
"Ref": "OrdersTableQueryRole"
}
]
}
},
"OrdersTableQueryRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"dynamodb.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/"
}
}
}
}
我需要帮助来使用上面提到的值填充 table 以及如何将提到的属性值作为参数传递。
如有任何帮助,我们将不胜感激。
谢谢
没有办法通过 CloudFormation 将行添加到 DynamoDB table。 CloudFormation 是一种旨在 create/manage 基础架构而非数据的工具。我建议在一个单独的过程中这样做。例如,如果您通过 CodePipeline 进行部署,您可以拥有一个在 CloudFormation 创建后运行的 CodeBuild 作业。该代码几乎可以做任何您想做的事情。
可以选择创建一个 custom resource or a resource provider,但虽然有可能,但我认为这不在其预期目的之内。
我们需要 custom cloudformation 资源来将条目添加到 Dynamo Table。
来自文档:
With Lambda functions and custom resources, you can run custom code in response to stack events (create, update, and delete).
This custom resource invokes a Lambda function and sends it the StackName property as input. The function uses this property to get outputs from the appropriate stack.
这是我为 1 个键创建的示例,需要一些小的改动:
我们需要两件事。
一,保存Lambda函数的堆栈。有了这个,当我们 add/remove/update 一个资源时,我们就没有在幕后调用这个 Lambda 的 cloudformation 资源。这通常一起进入单独的堆栈。
AWSTemplateFormatVersion: '2010-09-09'
Resources:
DynamoCfnLambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: '/'
Policies:
- PolicyName: dynamodbAccessRole
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:*
Resource: '*'
- Effect: Allow
Action:
- logs:*
Resource: '*'
CfnCrtUpdDltDynamodbDocumentLambda:
Type: AWS::Lambda::Function
Properties:
FunctionName: 'cfn-crt-upd-dlt-dynamodb-document'
Code:
ZipFile: >
const AWS = require("aws-sdk");
const response = require("./cfn-response");
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = function(event, context) {
console.log(JSON.stringify(event, null, 2));
var item = JSON.parse(event.ResourceProperties.DynamoItem);
var keyProperty = event.ResourceProperties.DynamoKeyProperty;
var tableName = event.ResourceProperties.DynamoTableName;
if (event.RequestType == "Create" || event.RequestType == "Update") {
console.log("item:", item);
var params = {
TableName: tableName,
Item: item
};
console.log("Creating or Updating Document");
docClient.put(params, function(err, data) {
if (err) {
console.log('error creating/updating document', err);
response.send(event, context, "FAILED", {}, tableName + '_' + item[keyProperty]);
} else {
response.send(event, context, "SUCCESS", {}, tableName + '_' + item[keyProperty]);
}
});
}
if (event.RequestType == "Delete") {
console.log("Deleting a Document");
var params = {
TableName: tableName,
Key: {
[keyProperty]: item[keyProperty]
}
};
docClient.delete(params, function(err, data) {
if (err) {
response.send(event, context, "FAILED", {});
} else {
response.send(event, context, "SUCCESS", {});
}
});
}
};
Handler: index.handler
Role: !GetAtt DynamoCfnLambdaRole.Arn
Runtime: nodejs10.x
Timeout: 60
其次,我们需要添加资源块 Custom::ThisCouldBeAnything
,ServiceToken
指向我们在上面创建的 Lambda Arn。每当我们
- 在任何 cloudformation 中添加一个新块,将使用 Create 调用 Lambda,这会在 Dynamo table. 中创建一个条目
- 从 Cloudformation 中删除块,Lambda 将使用 Delete 调用,从 Dynamo 中删除条目 Table。
- 更改资源块中的内容,例如更改 DynamoItem 中的内容,Lambda 将随更新一起调用。
对于要插入 Dynamo 的每条记录,我们都需要一个资源块。
Resources:
MyPhone223546421:
Type: Custom::CrtUpdDltDynamodbDocumentLambda
Properties:
ServiceToken: !GetAtt CfnCrtUpdDltDynamodbDocumentLambda.Arn
DynamoTableName: My-Table
DynamoKeyProperty: 'PhoneNumber'
DynamoItem: |
{
"PhoneNumber": "223546421",
"OrderNumber": "11545154",
"someKey": "someValue"
}
MyPhone784578745:
Type: Custom::CrtUpdDltDynamodbDocumentLambda
Properties:
ServiceToken: !GetAtt CfnCrtUpdDltDynamodbDocumentLambda.Arn
DynamoTableName: My-Table
DynamoKeyProperty: 'PhoneNumber'
DynamoItem: |
{
"PhoneNumber": "784578745",
"OrderNumber": "11547854",
"someKey": "someValue"
}