从Lambda函数(无服务器的nodejs)内部调用S3.waitFor()
函数时出现问题。我正在尝试使用一个休憩API中的S3.putObject()
异步地将文件写入S3,并使用S3.waitFor()
轮询另一个休憩API中的结果文件,以查看编写是否准备就绪/已完成。
请参见以下代码段:
...
S3.waitFor('objectExists', {
Bucket: bucketName,
Key: fileName,
$waiter: {
maxAttempts: 5,
delay: 3
}
}, (error, data) => {
if (error) {
console.log("error:" + JSON.stringify(error))
} else {
console.log("Success")
}
});
...
给出有效 bucketName和 invalid fileName,当代码在我的本地测试脚本中运行时,它在15秒(3秒x 5次重试)后返回错误,并产生如下结果:
error: {
"message": "Resource is not in the state objectExists",
"code": "ResourceNotReady",
"region": null,
"time": "2018-08-03T06:08:12.276Z",
"requestId": "AD621033DCEA7670",
"extendedRequestId": "JNkxddWX3IZfauJJ63SgVwyv5nShQ+Mworb8pgCmb1f/cQbTu3+52aFuEi8XGro72mJ4ik6ZMGA=",
"retryable": true,
"statusCode": 404,
"retryDelay": 3000
}
同时,当它在AWS lambda函数中运行时,它直接返回结果,如下所示:
error: {
"message": "Resource is not in the state objectExists",
"code": "ResourceNotReady",
"region": null,
"time": "2018-08-03T05:49:43.178Z",
"requestId": "E34D731777472663",
"extendedRequestId": "ONMGnQkd14gvCfE/FWk54uYRG6Uas/hvV6OYeiax5BTOCVwbxGGvmHxMlOHuHPzxL5gZOahPUGM=",
"retryable": false,
"statusCode": 403,
"retryDelay": 3000
}
如您所见,两者的retryable和statusCode值不同。
在lamba上,当文件不存在时,似乎总是获得statusCode 403。在我的本地计算机上,一切正常(每3秒重试5次,并收到statusCode 404)。
我想知道这是否与IAM角色有关。这是serverless.yml中我的IAM角色声明设置:
iamRoleStatements:
- Effect: "Allow"
Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:PutLogEvents"
- "ec2:CreateNetworkInterface"
- "ec2:DescribeNetworkInterfaces"
- "ec2:DeleteNetworkInterface"
- "sns:Publish"
- "sns:Subscribe"
- "s3:*"
Resource: "*"
如何通过lambda函数使其工作? 预先谢谢你!
答案 0 :(得分:0)
事实证明,关键在于如何为存储桶及其下的所有对象设置IAM角色。
基于AWS文档here,它指出S3.waitFor()
依赖于基础S3.headObject()
。
等待对象存在状态是通过每5秒(最多20次)定期调用底层的 S3.headObject()操作来实现的。
与此同时,S3.headObject()
本身依赖于HEAD Object API,该API具有以下规则,如AWS Docs here所述:
此操作需要 s3:GetObject 权限。有关更多信息,请转到Amazon Simple Storage Service开发人员指南中的在策略中指定权限。 如果您请求的对象不存在,Amazon S3返回的错误取决于您是否还具有s3:ListBucket权限。
- 如果您对存储桶具有s3:ListBucket 权限,则Amazon S3 将会返回HTTP状态代码 404(“没有这样的密钥”)错误。
- 如果您没有s3:ListBucket 权限,Amazon S3将返回 HTTP状态代码 403(“访问被拒绝”)错误。
这意味着我需要向包含对象的Bucket资源添加s3:ListBucket
动作,以便在对象不存在时能够获得响应404。
因此,我已经如下配置了cloudformation AWS :: IAM :: Policy资源,在其中我专门针对存储桶本身(即S3FileStorageBucket)添加了s3:Get*
和s3:List*
操作。
"IamPolicyLambdaExecution": {
"Type": "AWS::IAM::Policy",
"DependsOn": [
"IamRoleLambdaExecution",
"S3FileStorageBucket"
],
"Properties": {
"PolicyName": { "Fn::Join": ["-", ["Live-RolePolicy", { "Ref": "environment"}]]},
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect":"Allow",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": {
"Fn::Join": [
"",
[
"arn:aws:s3:::",
{
"Ref": "S3FileStorageBucket"
}
]
]
}
},
{
"Effect":"Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": {
"Fn::Join": [
"",
[
"arn:aws:s3:::",
{
"Ref": "S3FileStorageBucket"
},
"/*"
]
]
}
},
...
现在,我已经能够执行S3.waitFor()
,仅通过一个API调用就可以在存储桶下轮询文件/对象,并且仅在准备就绪时获取结果,或者在资源准备就绪后抛出错误。特定的超时时间。
这样,客户端实现将更加简单。因为它不必自己实施轮询。
希望有人发现它有用。谢谢。