DataSync StartExecutionAPI调用报错:ARN令牌无法解析问题咨询
在同一个AWS CDK栈中创建完DataSync的Locations、Tasks和Role后,尝试通过DataSync客户端调用栈内的任务,使用StartExecutionAPI时遇到ARN令牌解析错误。
代码片段
const client = new DataSyncClient(); const input = { TaskArn: TASK1.attrTaskArn, }; const command = new StartTaskExecutionCommand(input); (async () => { const response = await client.send(command); })();
错误信息
const exception = new InvalidRequestException({
^
InvalidRequestException: Invalid parameter: Malformed ARN: ${Token[TOKEN.110]}.
at de_InvalidRequestExceptionRes (/codebuild/output/src4271555059/src/node_modules/@aws-sdk/client-datasync/dist-cjs/index.js:1945:21)
at de_CommandError (/codebuild/output/src4271555059/src/node_modules/@aws-sdk/client-datasync/dist-cjs/index.js:1923:19)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at async /codebuild/output/src4271555059/src/node_modules/@smithy/middleware-serde/dist-cjs/index.js:35:20)
at async /codebuild/output/src4271555059/src/node_modules/@smithy/core/dist-cjs/index.js:165:18)
at async /codebuild/output/src4271555059/src/node_modules/@smithy/middleware-retry/dist-cjs/index.js:320:38)
at async /codebuild/output/src4271555059/src/node_modules/@aws-sdk/middleware-logger/dist-cjs/index.js:33:22)
at async /codebuild/output/src4271555059/src/lib/stacks/be-customer-migration-stack.ts:65:28 {
'$fault': 'client',
'$metadata': {
httpStatusCode: 400,
requestId: 'b124d220-8350-4bc5-9cb1-219211c65fea',
extendedRequestId: undefined,
cfId: undefined,
attempts: 1,
totalRetryDelay: 0
},
errorCode: 'InvalidParameter',
datasyncErrorCode: undefined,
__type: 'InvalidRequestException'
}
已尝试操作
- 用已创建任务的ARN硬编码替换
TASK1.attrTaskArn,调用返回200 OK,任务能在流水线synth阶段触发(使用流水线部署栈,非直接部署)。 - 推测部署时DataSync客户端无法解析ARN令牌。
疑问
- 是否因任务创建与执行同时进行导致该问题?
- 能否在同一栈中完成这两项操作?
问题原因
是的,问题根源就是任务创建和执行操作在CDK部署流程中同步进行。CDK在synth阶段生成CloudFormation模板时,TASK1.attrTaskArn还只是一个占位令牌(Token),没有实际ARN值。而你直接在栈的初始化代码里调用DataSync客户端,这个调用会在synth阶段就执行,此时令牌未被替换为真实ARN,自然抛出格式错误。
解决方案:使用CloudFormation自定义资源
可以在同一栈中完成任务创建和执行,但不能直接在栈初始化代码里调用API,需要借助CloudFormation自定义资源延迟执行任务启动操作,确保任务已创建完成(ARN已生成):
- 创建自定义资源Lambda函数:负责调用DataSync的
StartTaskExecutionAPI,接收任务ARN作为输入参数。 - 在CDK栈中定义自定义资源:将任务ARN作为参数传递给自定义资源,确保CloudFormation完成任务资源创建后,再触发Lambda函数执行任务启动。
示例代码
// 1. 创建自定义资源Lambda函数 const startTaskLambda = new lambda.Function(this, 'StartDataSyncTaskLambda', { runtime: lambda.Runtime.NODEJS_18_X, handler: 'index.handler', code: lambda.Code.fromInline(` const { DataSyncClient, StartTaskExecutionCommand } = require("@aws-sdk/client-datasync"); const client = new DataSyncClient({ region: process.env.AWS_REGION }); exports.handler = async (event) => { if (event.RequestType === 'Create' || event.RequestType === 'Update') { const taskArn = event.ResourceProperties.TaskArn; const command = new StartTaskExecutionCommand({ TaskArn: taskArn }); await client.send(command); } // 向CloudFormation发送成功响应 const response = { Status: 'SUCCESS', PhysicalResourceId: event.PhysicalResourceId || Date.now().toString(), StackId: event.StackId, RequestId: event.RequestId, LogicalResourceId: event.LogicalResourceId }; await fetch(event.ResponseURL, { method: 'PUT', body: JSON.stringify(response), headers: { 'Content-Type': '' } }); }; `), }); // 2. 给Lambda函数添加调用DataSync的权限 startTaskLambda.addToRolePolicy(new iam.PolicyStatement({ actions: ['datasync:StartTaskExecution'], resources: [TASK1.attrTaskArn], })); // 3. 创建自定义资源,关联Lambda函数和任务ARN new cr.CustomResource(this, 'StartDataSyncTaskCustomResource', { serviceToken: startTaskLambda.functionArn, properties: { TaskArn: TASK1.attrTaskArn, }, });
方案可行性说明
- CloudFormation会先完成Locations、Tasks、Role等基础资源的创建,确保
TASK1.attrTaskArn已变为真实ARN值。 - 自定义资源会在基础资源创建完成后触发Lambda函数,此时调用
StartTaskExecutionAPI能获取有效ARN,不会再出现令牌解析错误。
内容的提问来源于stack exchange,提问作者shreya sood

