Как получить доступ к хранилищу параметров aws из лямбды, используя node.js и aws-sdk
Я создал лямбда и шаблон формирования облака, который предоставляет лямбда доступ к хранилищу параметров и диспетчеру секретов. Когда я тестирую лямбду, у меня есть следующие функции вне функции export.handler:
function getParameterFromStore(param){
let promise = new Promise(function(resolve, reject){
console.log('++ ' + param.Path);
servmgr.getParametersByPath(param, function(err, data){
if(err){
reject(console.log('Error getting parameter: ' + err, err.stack));
} else {
resolve(data);
}
});
});
let parameterResult = promise.then(function(result){
console.log('---- result: '+ JSON.stringify(result));
return result;
});
return parameterResult;
};
servmgr
создается как var servmgr = new AWS.SSM();
Когда я вызываю эту функцию из функции export.handler, я делаю так:
myFirstParam = { Path : '/myPath/Service/servicesEndpoint'};
let endpointResult = getParameterFromStore(myFirstParam);
В лямбда-функции у меня есть функция получения параметра, определенного вне функции export.handler, обернутая в обещание.
Когда я запускаю / проверяю эту лямбду, возвращаемый объект всегда неопределен... Я получаю параметры [], но никаких значений.
2019-02-20T21:42:41.340Z 2684fe88-d552-4560-a477-6761f2de6717 ++ /myPath/Service/serviceEndpoint
2019-02-20T21:42:41.452Z 2684fe88-d552-4560-a477-6761f2de6717 ---- result: {"Parameters":[]}
Как вы получаете значения параметров, возвращаемые лямбда во время выполнения?
Обновить
основываясь на предложении / ответе Фалеса, я упростил лямбду до этого:
const getParameterFromStoreAsync = (param) => {
return new Promise((resolve, reject) => {
servmgr.getParametersByPath(param, (err, data) => {
if(err){
reject(console.log('Error getting parameter: ' + err, err.stack));
}
return resolve(data);
});
});
};
exports.handler = async(event, ctx, callback) => {
console.log('INFO[lambda]: Event: [' + JSON.stringify(event, null, 2) + ']');
console.log('this is the event' + JSON.stringify(event));
sfdcEndPointParam = { Path : '/PartnerBanking/Service/SfdcEndpoint'};
let myendpoint = await getParameterFromStoreAsync(sfdcEndPointParam);
console.log('### endpoint path: ' + JSON.stringify(myendpoint));
done = ()=>{}
callback(null, done());
};
Я все еще вижу пустой массив, возвращаемый в моих тестах:
### endpoint path: {"Parameters":[]}
Я также переместил функцию в обратный вызов, как
exports.handler = (event,ctx, callback){
done = async()=>{
console.log('this is the event' + JSON.stringify(event));
sfdcEndPointParam = { Path : '/PartnerBanking/Service/SfdcEndpoint'};
let myendpoint = await getParameterFromStoreAsync(sfdcEndPointParam);
console.log('### endpoint path: ' + JSON.stringify(myendpoint));}
}
callback(null, done());
Тот же результат... пустой массив. Какие-нибудь дополнительные вещи попробовать?
1 ответ
Это потому что ваш getParameterFromStore
возвращается до вашего then()
код выполняется, таким образом parameterResult
является undefined
, Если вы не хотите слишком сильно изменять свой код, я бы вернул созданное вами обещание, например:
function getParameterFromStore(param){
return new Promise(function(resolve, reject){
console.log('++ ' + param.Path);
servmgr.getParametersByPath(param, function(err, data){
if(err){
reject(console.log('Error getting parameter: ' + err, err.stack));
} else {
resolve(data);
}
});
});
};
И, наконец, на клиенте вашей функции вы можете получить такой результат:
const myFirstParam = { Path : '/myPath/Service/servicesEndpoint'}
getParameterFromStore(myFirstParam).then(console.log)
Однако при кодировании в NodeJS я настоятельно рекомендую вместо этого использовать async/await, чтобы вы могли выйти из ада Promise (изменяйте Promise после Promise для достижения чего-то "синхронно")
При использовании async/await вы можете создать свой код, как если бы он был синхронным. Вот реорганизованная версия вашего примера, использующая async/await и функции стрелок:
const getParameterFromStore = param => {
return new Promise((resolve, reject) => {
console.log('++ ' + param.Path);
servmgr.getParametersByPath(param, (err, data) => {
if (err) {
console.log('Error getting parameter: ' + err, err.stack)
return reject(err);
}
return resolve(data);
});
})
}
exports.handler = async (event) => {
const endpointResult = await getParameterFromStore(event.someAttributeFromTheEventThatYouWantToUse)
console.log(endpointResult)
};
РЕДАКТИРОВАТЬ: После того, как ОП исправил первую проблему, я создал рабочий пример самостоятельно. Оказалось, что OP вызывал API неправильно.
Вот полный рабочий пример:
'use strict';
const AWS = require('aws-sdk')
AWS.config.update({
region: 'us-east-1'
})
const parameterStore = new AWS.SSM()
const getParam = param => {
return new Promise((res, rej) => {
parameterStore.getParameter({
Name: param
}, (err, data) => {
if (err) {
return rej(err)
}
return res(data)
})
})
}
module.exports.get = async (event, context) => {
const param = await getParam('MyTestParameter')
console.log(param);
return {
statusCode: 200,
body: JSON.stringify(param)
};
};
Следите за Name
атрибут, который должен быть предоставлен как часть вызова API для метода ServiceManager.getAttribute.
Этот атрибут указан в официальных документах
Я запустил это сам и вот вывод в CloudWatch Logs:
Как видите, значение было успешно возвращено.
Надеюсь это поможет!
Если ваша лямбда развернута в VPC, убедитесь, что к нему подключена группа безопасности и разрешен исходящий трафик. Он сможет автоматически получить доступ к хранилищу параметров.
https://aws.amazon.com/premiumsupport/knowledge-center/lambda-vpc-parameter-store/
Более простое решение:
const getParameterFromStore = (params) => servmgr.getParametersByPath(params).promise();
const myFirstParam = { Path : '/myPath/Service'};
getParameterFromStore(myFirstParam).then(console.log);
Как видите, сам SDK предоставляет служебные функции, которые вы можете использовать в зависимости от ваших потребностей в асинхронном или синхронном режиме.
Надеюсь, это поможет.
- м