Я новичок в Node.js, работаю с примером проекта стороннего поставщика и пытаюсь использовать Azure Key Vault для хранения значений конфигурации.
У меня возникли проблемы с получением процесса wait перед выполнением остальных. Постараюсь подробно описать, насколько знаю.
пример проекта имеет файл с именем agent.js, который является стартовой страницей/файлом. На строка 16 (agent_config = require('./config/config.js')[process.env.LP_ACCOUNT][process.env.LP_USER]) вызывает файл конфигурации со значениями. Я пытаюсь установить эти значения с помощью Key Vault. Я пробовал множество комбинаций функций вызова и даже реализацию async / await, но значение agent_config всегда содержит объект [Promise], а не данные, возвращаемые Key Vault.
Если я прав, это связано с тем, что само Key Vault также использует async / await, и файл конфигурации возвращается до того, как возвращаются значения Key Vault.
Как можно добавить/внедрить Key Vault в такой ситуации?
Вот что я пробовал:
Сначала обновлен агент.js до
let agent_config = {};
try {
agent_config = require('./config/config.js')['123']['accountName'];
} catch (ex) {
log.warn(`[agent.js] Error loading config: ${ex}`)
}
console.info(agent_config);
./config/config.js
const KeyVault = require('azure-keyvault');
const msRestAzure = require('ms-rest-azure');
const KEY_VAULT_URI = 'https://' + '{my vault}' + '.vault.azure.net/' || process.env['KEY_VAULT_URI'];
function getValue(secretName, secretVersion) {
msRestAzure.loginWithAppServiceMSI({ resource: 'https://vault.azure.net' }).then((credentials) => {
const client = new KeyVault.KeyVaultClient(credentials);
client.getSecret(KEY_VAULT_URI, secretName, secretVersion).then(
function (response) {
return response.Value;
});
});
}
module.exports = {
'123': {
'accountName': {
accountId: getValue('mySecretName', '')
}
}
};
Результаты
{ accountsId: undefined }
Сделал получить значение функцией async и обернул ее вокруг другой функции (попробовал без обертки, тоже не сработало)
./config/config.js
const KeyVault = require('azure-keyvault');
const msRestAzure = require('ms-rest-azure');
const KEY_VAULT_URI = 'https://' + '{my vault}' + '.vault.azure.net/' || process.env['KEY_VAULT_URI'];
async function getValue(secretName, secretVersion) {
msRestAzure.loginWithAppServiceMSI({ resource: 'https://vault.azure.net' }).then((credentials) => {
const client = new KeyVault.KeyVaultClient(credentials);
client.getSecret(KEY_VAULT_URI, secretName, secretVersion).then(
function (response) {
return response.Value;
});
});
}
async function config() {
module.exports = {
'123': {
'accountName': {
accountId: await getValue('mySecretName', '')
}
}
};
}
config();
Результаты
{}
Сделал получить значение функцией async и обернул ее вокруг другой функции (попробовал без обертки, тоже не сработало)
./config/config.js
const KeyVault = require('azure-keyvault');
const msRestAzure = require('ms-rest-azure');
const KEY_VAULT_URI = 'https://' + '{my vault}' + '.vault.azure.net/' || process.env['KEY_VAULT_URI'];
async function getValue(secretName, secretVersion) {
return msRestAzure.loginWithAppServiceMSI({ resource: 'https://vault.azure.net' })
.then((credentials) => {
const client = new KeyVault.KeyVaultClient(credentials);
return client.getSecret(KEY_VAULT_URI, secretName, secretVersion).then(
function (response) {
return response.Value;
});
});
}
module.exports = {
'123': {
'accountName': {
accountId: getValue('mySecretName', '')
}
}
};
config();
Результаты
{ accountId: { <pending> } }
Я пробовал много других способов, таких как module.exports = async (value) =< {...} (безуспешно нашел через другие вопросы/решения.
Я начинаю думать, что мне нужно немного «подождать» agent.js, но я не нашел хорошей информации об этом.
Любая помощь будет здорово!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Одна из проблем заключается в том, что ваша функция getValue ничего не возвращает, поскольку ваши возвращаемые значения должны быть явными.
(и без возврата обещания ждать нечего)
async function getValue(secretName, secretVersion) {
return msRestAzure.loginWithAppServiceMSI({ resource: 'https://vault.azure.net' })
.then((credentials) => {
const client = new KeyVault.KeyVaultClient(credentials);
return client.getSecret(KEY_VAULT_URI, secretName, secretVersion).then(
function (response) {
return response.Value;
});
});
}
Вы также можете уйти с менее явным возвратом, используя стрелочные функции.
const getValue = async (secretName, secretVersion) =>
msRestAzure.loginWithAppServiceMSI({ resource: 'https://vault.azure.net' })
.then(credentials => {
const client = new KeyVault.KeyVaultClient(credentials);
return client.getSecret(KEY_VAULT_URI, secretName, secretVersion)
.then(response => response.Value);
});
Представление чтения Azure Key Vault, которое является асинхронным, означает, что вся ваша конфигурация читается асинхронно. Вы ничего не можете сделать, чтобы обойти это. Это будет означать, что код, который использует конфигурацию, должен будет обрабатывать ее соответствующим образом. Вы начинаете с экспорта асинхронной функции, которая вернет конфигурацию.
async function getConfig() {
return {
'123': {
'accountName': {
accountId: await getValue('mySecretName', '')
}
}
};
}
module.exports = getConfig;
В коде вашего агента вы вызываете эту функцию. Это будет означать, что ваш код агента также должен быть обернут в функцию, поэтому, возможно, что-то вроде этого.
const Bot = require('./bot/bot.js');
const getConfig = require('./config/config.js');
getConfig().then(agentConfig => {
const agent = new Bot(agentConfig);
agent.on(Bot.const.CONNECTED, data => {
log.info(`[agent.js] CONNECTED ${JSON.stringify(data)}`);
});
});
добавил это как тест 3
Вы делаете это неправильно в тесте 3. Вы должны подождать getValue. Но это приведет к тому, что ваш конфиг должен быть обернут внутри асинхронной функции, что-то вроде теста 1. Кстати, вы делаете это неправильно в тесте 1: не устанавливайте module.exports там, вместо этого возвращайте объект, который будет назначен module.exports.
добавил пример использования в мой ответ
@lecstor спасибо за использование примера. Когда я использую его как есть, я получаю следующую ошибку "Unexpected identifier". Кажется, это function async getConfig() {...} Когда я переключаю порядок function и async, я не получаю ошибку, однако я получаю результат { accountId: undefined }. Я что-то пропустил?
@RoLYroLLs, может быть, у вас нет секрета с таким именем в вашем хранилище Azure?
@RoLYroLLs, вы можете проверить, сработает ли это? gist.github.com/Притилендер/7ae1d68331b5f76c818e601760bd2db2
упс, спасибо, исправлена опечатка. Не уверен насчет неопределенного accountId сейчас. Я бы добавил ведение журнала в getValue, чтобы проверить, что credentials и response соответствуют ожиданиям.
@lecstor Скрипт от Pritilender действительно работает. Не уверен, почему.
response => response.Value похоже, что «значение» должно быть в нижнем регистре
@lecstor твой скрипт тоже работает!! Я нашел еще одну опечатку, которая сбила меня с толку. Ваша функция getValue имеет дополнительный } в конце. Я думал, вы забыли вводную в самом начале. Вместо этого я удалил последний }, и это сработало. Я не могу отредактировать ваше сообщение, так как изменился только 1 символ.
@RoLYroLLs, мой сценарий просто асинхронно / ожидает перезаписи лекстора. Несмотря на то, что вам удалось заставить его код работать, я бы посоветовал не использовать этот стиль кодирования, поскольку он делает код немного нечитаемым. Без обид, лекстор, просто если вы уже заявляете, что функция асинхронна, то используйте в ней await вместо вложенных обратных вызовов обещаний.
@Pritilender, все хорошо, я согласен с этим, я просто пытался сохранить код как можно ближе к исходному сообщению.
Пакет azure-keyvault устарел в пользу новых пакетов для отдельной работы с ключами, секретами и сертификатами Keyvault. В вашем сценарии вы можете использовать новый пакет @azure/keyvault-секреты для взаимодействия с Key Vault и новый пакет @лазурь/идентификация для создания учетных данных.
const { SecretClient } = require("@azure/keyvault-secrets");
const { DefaultAzureCredential } = require("@azure/identity");
async function getValue(secretName, secretVersion) {
const credential = new DefaultAzureCredential();
const client = new SecretClient(KEY_VAULT_URI, credential);
const secret = await client.getSecret(secretName);
return secret.value;
}
DefaultAzureCredential предполагает, что вы установили следующие переменные env
Чтобы попробовать другие учетные данные, см. ридми для @azure/identity Если вы переходите со старого пакета azure-keyvault, ознакомьтесь с руководство по миграции, чтобы понять основные изменения.
Спасибо. Однако это приводит к тому же самому.
{ accountId: Promise { <pending> } }