Node.js箭头函数中基于InstanceId获取EC2实例Platform值
解决AWS Lambda中提取EC2实例Platform字段的问题
问题核心分析
你遇到的问题主要源于两个关键点:
- 代码存在函数名笔误:定义的实例信息查询函数是
InstanceIds,但调用时误用了getInstanceInfo,导致逻辑混乱 - 对
Promise.all返回值结构理解有误:instances是实例对象的数组,不能直接通过instances.platform访问单个实例字段,需遍历数组或通过索引定位
另外要注意:CloudTrail的RunInstances事件响应中已经直接包含platform字段,完全不需要额外调用describeInstances,能大幅减少API调用开销。
方案一:直接从CloudTrail事件提取Platform(推荐)
既然event.detail.responseElements.instancesSet.items里的每个实例对象已经自带platform字段,直接提取即可:
const AWS = require('aws-sdk'); exports.handler = async (event) => { var newTags = []; newTags.push({ Key: 'Created', Value: event.detail.eventTime }); if (event.source === 'aws.ec2' && event.detail.eventName === 'RunInstances') { // 遍历事件中的每个实例,直接提取platform字段 await Promise.all(event.detail.responseElements.instancesSet.items.map(async (instanceItem) => { const platform = instanceItem.platform; // 拼接OS标签到现有标签列表 const instanceTags = [...newTags, { Key: 'OS', Value: platform }]; // 调用更新标签函数,传入必要的实例ID和VPC ID await ec2Update({ InstanceId: instanceItem.instanceId, VpcId: instanceItem.vpcId }, instanceTags); })); } return "tags have been set!"; }; // 以下保留你原有的ec2Update、getVpc、setTags、InstanceIds函数 var ec2Update = (instance, tags) => new Promise(async (resolve) => { var myTags = JSON.parse(JSON.stringify(tags)); var ignoreKeysLowerCase = ['name','aws:cloudformation:stack-name','aws:cloudformation:stack-id','aws:cloudformation:logical-id']; var vpc = await getVpc({ VpcIds: [instance.VpcId] }); vpc.Tags.map(x => { if (!ignoreKeysLowerCase.includes(x.Key.toLowerCase())) { myTags.push(x) } }); await setTags(instance.InstanceId, myTags); resolve(); }); var InstanceIds = (params) => new Promise((resolve) => { var aws = new AWS.EC2({ region: process.env.AWS_REGION }).describeInstances(params); aws.on('success', r => { resolve(r.data.Reservations[0].Instances[0]); }).on('error', e => { console.log('error in describeInstances', e.message); }).send(); }); var getVpc = (params) => new Promise((resolve) => { var aws = new AWS.EC2({ region: process.env.AWS_REGION }).describeVpcs(params); aws.on('success', r => { resolve(r.data.Vpcs[0]) }).on('error', e => { console.log('error in describeVpcs', e.message); }).send(); }); var setTags = (instanceId, tags) => new Promise((resolve) => { var params = { Resources: [instanceId], Tags: tags }; console.log('setting the following tags', params); var aws = new AWS.EC2({ region: process.env.AWS_REGION }).createTags(params); aws.on('success', r => { resolve(r.data); }).on('error', e => { console.log('error in setTags', e.message); }).send(); });
方案二:通过describeInstances获取Platform(如需验证数据)
如果必须调用describeInstances获取最新实例信息,需先修正函数名笔误,同时注意AWS SDK返回的字段是首字母大写的Platform(而非CloudTrail事件里的小写platform):
const AWS = require('aws-sdk'); exports.handler = async (event) => { var newTags = []; newTags.push({ Key: 'Created', Value: event.detail.eventTime }); if (event.source === 'aws.ec2' && event.detail.eventName === 'RunInstances') { // 修正函数名:将getInstanceInfo改为正确的InstanceIds var instances = await Promise.all(event.detail.responseElements.instancesSet.items.map(x => InstanceIds({ InstanceIds: [x.instanceId] }))); await Promise.all(instances.map(instance => { // 提取Platform字段,Linux实例可能无该字段,需加默认值 const platform = instance.Platform || 'linux'; const instanceTags = [...newTags, { Key: 'OS', Value: platform }]; return ec2Update(instance, instanceTags); })); } return "tags have been set!"; }; // 以下保留你原有的ec2Update、getVpc、setTags、InstanceIds函数 var ec2Update = (instance, tags) => new Promise(async (resolve) => { var myTags = JSON.parse(JSON.stringify(tags)); var ignoreKeysLowerCase = ['name','aws:cloudformation:stack-name','aws:cloudformation:stack-id','aws:cloudformation:logical-id']; var vpc = await getVpc({ VpcIds: [instance.VpcId] }); vpc.Tags.map(x => { if (!ignoreKeysLowerCase.includes(x.Key.toLowerCase())) { myTags.push(x) } }); await setTags(instance.InstanceId, myTags); resolve(); }); var InstanceIds = (params) => new Promise((resolve) => { var aws = new AWS.EC2({ region: process.env.AWS_REGION }).describeInstances(params); aws.on('success', r => { resolve(r.data.Reservations[0].Instances[0]); }).on('error', e => { console.log('error in describeInstances', e.message); }).send(); }); var getVpc = (params) => new Promise((resolve) => { var aws = new AWS.EC2({ region: process.env.AWS_REGION }).describeVpcs(params); aws.on('success', r => { resolve(r.data.Vpcs[0]) }).on('error', e => { console.log('error in describeVpcs', e.message); }).send(); }); var setTags = (instanceId, tags) => new Promise((resolve) => { var params = { Resources: [instanceId], Tags: tags }; console.log('setting the following tags', params); var aws = new AWS.EC2({ region: process.env.AWS_REGION }).createTags(params); aws.on('success', r => { resolve(r.data); }).on('error', e => { console.log('error in setTags', e.message); }).send(); });
关键注意点
- Linux实例的
describeInstances响应通常不会返回Platform字段,需添加默认值避免undefined - 确保Lambda执行角色拥有
ec2:DescribeInstances和ec2:CreateTags权限
之前尝试失败的原因
- 额外传递
x.platform给getInstanceInfo:InstanceIds函数仅接收一个参数,多余参数不会被处理,因此无效 - 直接读取
instances.platform:instances是数组,不是单个实例对象,必须遍历数组或通过索引(如instances[0].Platform)访问 - 将
x.platform作为InstanceId传入:会导致describeInstances用windows作为实例ID调用,自然触发过滤条件错误
内容的提问来源于stack exchange,提问作者JParrish
相关产品推荐
相关产品推荐

