Firebase-tools: Принять файл JSON для функций: config: set

Созданный на 20 июл. 2017  ·  37Комментарии  ·  Источник: firebase/firebase-tools

В настоящее время можно получить всю конфигурацию функций в виде файла JSON с помощью firebase functions:config:get , но мы должны вручную встроить каждую переменную при использовании команды firebase functions:config:set , что делает ее практически неприменимой при работе с разные среды.

В идеале мы должны уметь:

firebase functions:config:get > config.json
firebase functions:config:set -f config.json

Самый полезный комментарий

Спасибо, что поделились! @laurenzlong
Я хотел импортировать из файла, поэтому использовал такую ​​команду.

firebase functions:config:set service_account="$(cat service-account.json)"

Я импортировал json-файл служебного аккаунта в Firebase Cloud Functions, потому что хотел использовать API управления пользователями Firebase Admin SDK.

Все 37 Комментарий

Я согласен с @jpreynat , мы переменную конфигурации перед развертыванием в нашей производственной среде. Привязка config: к нашим настраиваемым сценариям развертывания с config.json была бы неплохой функцией, которую можно было бы добавить.
Есть ли какие-то обходные пути прямо сейчас, может быть, в конфигурации?

Похоже, вы пытаетесь реплицировать конфигурацию между проектами. Подойдет ли вам firebase functions:config:clone ?

Чтобы дать некоторый контекст, мы намеренно отклонились от конфигурации на основе файлов, потому что мы думаем, что она поощряет плохие методы (а именно, хранить файл, полный секретов, хранящихся в вашем коде, потенциально даже проверенных в вашем исходном репозитории).

Что бы вы подумали о каком-то способе (механика подлежит уточнению) для объявления «требуемых» переменных конфигурации - и если вы попытаетесь выполнить развертывание без требуемой конфигурации в текущем проекте, произойдет ошибка, прежде чем что-либо будет изменено. Решит ли это ваши основные проблемы? Если нет, то почему файл особенно полезен для вас?

@mbleigh Это именно то, чего я не знал, что хочу. Хорошая идея!
Вероятно, данное / то, что вы имели в виду под «Механикой TBD», но: Определение структуры ключей / конфигурации в каком-либо файле в нашем проекте, а не удаленно, чтобы он прошел через процесс проверки git / PR, как и все остальное.
@jpreynat Извините за проблему с захватом

@laurenzlong Спасибо за совет, но мы не пытаемся дублировать конфиг.
Наша основная задача - обновить конфигурацию различных проектов в зависимости от стадии развертывания.
Итак, в основном у нас есть файл конфигурации для каждой среды (dev, staging и prod), и мы устанавливаем конфигурацию Firebase соответственно (для PR нажимайте master и теги).

@mbleigh Спасибо за информацию.
Однако мы не совсем уверены, как мы можем хранить все эти env иначе, чем с помощью файлов конфигурации.
В настоящее время они отформатированы как JSON для простоты чтения, но мы думаем отформатировать их как пары ключ / значение, чтобы передать их напрямую команде functions:config:set .
Я согласен с вами, что это не более безопасно, чем передача файла JSON.
Есть ли у вас какие-либо рекомендации о том, как мы могли бы хранить переменные нашей среды для разных этапов, кроме использования файлов?

@ahaverty Не беспокойтесь, я рад, что это можно обсудить здесь.

@jpreynat при запуске functions:config:set сохраняется вместе с текущим проектом. Если вы используете firebase use для переключения между проектами, ваша конфигурация будет постоянной. Таким образом, вы можете запустить set один раз для каждого проекта, и тогда он всегда будет там. Это должно решить проблему «разные конфигурации для разных сред», так что, может быть, я не понимаю настоящую проблему?

@jpreynat Я собираюсь закрыть этот вопрос на данный момент, но, пожалуйста, откройте его повторно, если мы с Майклом неправильно поняли ваш запрос.

@laurenzlong @mbleigh Извините, что я не ответил быстро в этой теме.
На данный момент мы нашли обходной путь для этой проблемы, но вот контекст, чтобы прояснить мой запрос:

Мы развертываем наше приложение с помощью Travis (обратите внимание, что это было бы здорово с любым CI или даже локально). Поскольку мы развертываем наше приложение на разных этапах в зависимости от ветки и тега, было бы здорово иметь возможность использовать другой файл JSON в зависимости от среды.
Например, это позволит выполнить либо firebase config:set -f staging.json или firebase config:set -f prod.json зависимости от этого условия.
Нашим обходным решением было использование firebase в качестве модуля узла, но нам все равно нужно встроить нашу конфигурацию JSON, которая подвержена ошибкам.

Привет, @jpreynat, я все еще немного смущен твоим ответом. После того, как вы установили конфигурацию один раз, она всегда остается там, даже при развертывании, если вы явно не отмените установку значений конфигурации, запустив функции firebase

Может кто-нибудь снова открыть это? %) @jpreynat @mbleigh Это действительно одна из вещей, которой не хватает. Atm У меня есть около 15 переменных конфигурации (и еще больше), и это будет очень удобно, если functions:config:set может каким-то образом принимать JSON.

Большое количество голосов от нас за предложение @mbleigh об "объявлении" обязательных "переменных конфигурации - и если вы попытаетесь выполнить развертывание без требуемой конфигурации в текущем проекте, произойдет ошибка, прежде чем что-либо будет изменено".
Это тоже стало проблемой для нас, но это решило бы все наши проблемы и отлично вписалось бы в процесс контроля версий / проверки 👍

https://medium.com/@AllanHasegawa/setting -config-for-firebase-cloud-functions-with-json-136f455e7c69

Привет, @yaronyosef. Вы можете напрямую functions: config : set, просто вам нужно отформатировать его так, как это подходит для вашей платформы. Для Linux должно работать следующее:

firebase functions:config:set foo='{"bar":"something","faz":"other"}'

Спасибо, что поделились! @laurenzlong
Я хотел импортировать из файла, поэтому использовал такую ​​команду.

firebase functions:config:set service_account="$(cat service-account.json)"

Я импортировал json-файл служебного аккаунта в Firebase Cloud Functions, потому что хотел использовать API управления пользователями Firebase Admin SDK.

Классный вариант использования! Спасибо, что поделился!

Мы также предпочли бы отслеживать несекретные конфигурации через Git, где зафиксированные файлы конфигурации времени выполнения JSON (для нескольких сред) будут авторитетными, а среда CI затем применит functions:config:set из файла, соответствующего конкретной среде (и каждая среда соответствует отдельному проекту Firebase).

Если вы храните конфигурации в git, их несложно прочитать во время выполнения функций. Просто поместите их в configs/<project_id>.json а затем:

let config = {};
try {
  config = require(`./configs/${process.env.GCLOUD_PROJECT}.json`);
} catch (e) {
  console.log('No config found for project', process.env.GCLOUD_PROJECT);
}

Конфигурация времени выполнения, используемая Firebase, специально разработана, чтобы избежать регистрации конфигурации в git, поскольку (особенно с секретами) мы обнаружили, что это шаблон, который вызывает больше проблем, чем решает.

Это правда, хотя тогда мы вообще больше не используем Config API для этой цели. Может быть полезно по-прежнему использовать Config API для хранения конфиденциальных значений (что кажется подходящим вариантом использования на основе документов Firebase) и загружать как исходные, так и неотслеживаемые значения одним и тем же способом (то есть через config() предоставляется firebase-functions ).

В настоящее время я использую следующую однострочную строку, чтобы скормить все .runtimeconfig в functions:config:set :

firebase functions:config:set $(jq -r 'to_entries[] | [.key, (.value | tojson)] | join("=")' < .runtimeconfig/${FIREBASE_ENV}.json)

где FIREBASE_ENV - это имя среды, используемой при развертывании (например, dev ). Было бы неплохо иметь возможность еще больше сократить это, например

firebase functions:config:set -f .runtimeconfig/${FIREBASE_ENV}.json

В конечном счете, даже в этом может не быть необходимости, если в Config API включены простые в использовании контрольные журналы всех изменений (пожалуйста, поправьте меня, если это уже так, я хотел бы изучить это).

Итак, как это продвигается? 😄

Хотелось бы, чтобы предложение @mbleigh все еще было реализовано! У нас постоянно возникают проблемы, когда мы забываем установить конфигурации для целей, не относящихся к разработчикам.

Спасибо за нить. Пока не о чем сообщать, но я снова подниму этот вопрос на наших собраниях по планированию, чтобы посмотреть, сможем ли мы начать в этом направлении прогресс.

Я проверяю свою конфигурацию с помощью файла схемы JSON, чтобы убедиться, что в ней есть все ожидаемые значения. Эта проверка является частью моего конвейера CI и предотвращает развертывание в случае сбоя. Если вы, как и я, используете TypeScript для написания своих функций, вы можете сгенерировать схему JSON из своих типов.

Он отлично работает с ограничением, что конфигурация функций принимает только строки, поэтому схема не может проверить, является ли значение конфигурации числом. Для логических значений это нормально, потому что я могу использовать перечисление с "true" и "false" в качестве единственных допустимых значений.

См. Мою конфигурацию CircleCI и это сообщение в блоге для справки.

@hgwood спасибо, что поделился! Мы обязательно добавим это и в наш CI.

Просто хотел оставить свое решение этой «проблемы» и свои мысли по поводу обсуждения:

  1. Я понимаю, что секретные / конфиденциальные значения НЕ должны храниться в репо. Мое решение предназначено только для несекретных значений. Секретные значения устанавливаются вручную, но способ пометки значений конфигурации по мере необходимости был бы замечательным для этих секретных значений.
  2. Я думаю, это важнее, чем некоторые думают. Это PITA - вручную устанавливать отдельные значения конфигурации для разных проектов среды развертывания и не иметь возможности одновременно просматривать / сравнивать их. Определение конфигураций в файлах делает процесс НАМНОГО меньше хлопот.
  3. Я думаю, что добавление редактора конфигурации функций в веб-консоль значительно улучшило бы это, но было бы очень хорошо, если бы существовал способ одновременного просмотра конфигураций для нескольких проектов, чтобы вы могли легко сравнивать конфигурации для разных сред развертывания.
  4. Я всегда говорил, что firebase должна позволять определять среды в рамках одного проекта, поэтому вам не нужно использовать несколько проектов в качестве сред развертывания. Если бы он существовал, было бы очень легко одновременно просматривать конфигурации для нескольких сред в рамках одного проекта.
  5. У моего решения, вероятно, есть проблемы, не доверяйте моему коду дословно, но мне нравится общая концепция.

Мое решение

Я использую каскадные файлы конфигурации yaml, которые полезны для значений по умолчанию и значений, которые применяются ко всем конфигурациям независимо от среды развертывания.

./config/default.yml

app:
  name: My App
featureFlags:
  someFeature:
    enabled: false

./config/dev.yml (аналогичные файлы конфигурации для других сред развертывания)

imports:
  - {resource: default.yml}
app:
  environmentName: Development
services:
  someOtherService:
    baseUrl: https://dev.someotherservice.com/api
featureFlags:
  someFeature:
    enabled: true

Затем я написал небольшой скрипт узла, который загружает разрешенную конфигурацию и возвращает разделенный пробелами список пар ключ = значение.

yaml_to_keyval.ts

import * as configYaml from "config-yaml"
import * as flat from "flat"


const yamlFile = process.argv[2]
const config = configYaml(yamlFile)
const flatConfig = flat(config)

const key_val_list = Object.keys(flatConfig).map(function(key){
    return `${key}=${flatConfig[key]}`
})

console.log(key_val_list.join(' '))

Во время развертывания CI я использую этот сценарий оболочки bash для получения пар ключ = значение и установки их с помощью functions: config : set

# env is set to the desired deployment environment (eg "dev"), which is passed as an argument to the CI script command
config_in="$(readlink -f ./config/$env.yml)"
key_vals="$(ts-node ./scripts/node/yaml_to_keyval.ts $config_in)"
firebase functions:config:set $key_vals

@kanemotos Мне нравится ваше решение cat , но разве вы не сталкивались с ошибкой Precondition check failed при попытке загрузить файл сертификата?

По этим причинам мы закончили использовать Deployment Manager.

Устанавливаем всю конфигурацию через "config Yaml" для DM. Затем DM создает соответствующие конфигурации и переменные среды выполнения, а firebase deploy извлекает и устанавливает их значения во время развертывания без необходимости использования firebase config:set вообще. Это также позволяет нам настраивать другие ресурсы (например, сегменты и их контроль доступа) и устанавливать их значения в RC без необходимости передавать их внешнему шаблону. Кроме того, это позволяет нам использовать camelCase config и имена переменных.

Единственный раз, когда мы устанавливаем значение извне, - это когда нам нужно передать (зашифрованный) ключ учетной записи службы через конфигурацию времени выполнения, потому что DM не может надежно зашифровать значения. Но мы по-прежнему используем для этого gcloud beta runtime-config configs variables set (после развертывания DM и до firebase deploy ), а не firebase config:set , потому что первый принимает стандартный вывод от KMS.

Я просто хотел добавить - читая это, кажется, что некоторые люди упустили важный момент, который приводит к некоторой путанице. Было бы действительно полезно, если бы это тоже было разъяснено в документации.

По сути, functions.config() сохраняется между _deployments_, но ТАКЖЕ может быть установлено отдельно между разными проектами firebase!

Это означает, что для сред разработки, промежуточной и производственной среды вы должны настроить несколько идентичных проектов Firebase (вместо использования многосайтового хостинга или развертывания в ОДНОМ проекте ... 👎), каждый из которых постоянно содержит свои собственные - разные - переменные среды. .

После того, как вы установили псевдонимы (или просто переключились между проектами с помощью firebase use ), вы можете развернуть одно и то

Затем вы можете установить отдельные конфигурации среды для каждой, например:
firebase -P dev config:set - установить переменные для среды разработки.
firebase -P prod config:set - установить переменные для вашего производственного окружения ...

Затем вы можете развернуть одно и то же репо дважды, например:
firebase deploy -P dev
firebase deploy -P prod
и они оба будут развернуты в своем соответствующем проекте Firebase и будут содержать свою собственную отдельную конфигурацию среды, которая будет сохраняться между развертываниями.

Да, мы тоже так делаем. Отдельные проекты для dev / test / prod.

Просто поделитесь своим ванильным JS-решением, которое работает в зависимости от платформы, на которой вы разрабатываете (Windows, MacOS, Linux):

Использование отдельных проектов для dev / test / prod.

/.firebaserc

{
  "projects": {
    "dev": "my-project-name-dev",
    "test": "my-project-name-test",
    "prod": "my-project-name-prod"
  }
}

Файлы конфигурации

JSON-файлы в папке /functions/config :

/functions/config/config.dev.json 
/functions/config/config.test.json 
/functions/config/config.prod.json 
/functions/config/config.SAMPLE.json <-- only file tracked in git

Example content:
{
    "google": {
        "key": "my-api-key",
        "storage_bucket": "firebase-storage-bucket"
    },
    "another_vendor": {
        "my_prop": "my value"
    },
    ...
}

/functions/set-config.js

const fs = require('fs');
const env = process.argv[2];

const configPath = `./config/config.${env}.json`;

if (!(configPath && fs.existsSync(configPath))) {
    return;
}

const collectConfigLines = (o, propPath, configLines) => {
    propPath = propPath || '';
    configLines = configLines || [];
    for (const key of Object.keys(o)) {
        const newPropPath = propPath + key;
        if (typeof o[key] === 'object') {
            collectConfigLines(o[key], newPropPath + '.', configLines);
        } else if (o[key] != null && o[key] !== '') {
            configLines.push(`${newPropPath}=${JSON.stringify(o[key])}`);
        }
    }
}

const config = require(configPath);
const configLines = [];
collectConfigLines(config, '', configLines);

const cp = require('child_process');
cp.execSync(`firebase -P ${env} functions:config:set ${configLines.join(' ')}`);

/functions/package.json

...
"scripts": {
    "config:set:dev": "node set-config dev",
    "config:set:test": "node set-config test",
    "config:set:prod": "node set-config prod",
    ...
},
...

Если кто-то все еще ищет, есть метод, использованный в этой средней статье https://medium.com/indielayer/deploying-environment-variables-with-firebase-cloud-functions-680779413484. Спас мою жизнь.

Чего мне лично не хватает, так это возможности установить переменную конфигурации без развертывания. У нас есть конвейер CICD, который выполняет развертывание в наших различных средах, и мы не хотим, чтобы разработчик создавал код локально и развертывал его, особенно в производственной среде. Вот как все ломается.

Кроме того, если мы захотим изменить существующую переменную позже, при разработке какой-либо функции, прямо сейчас у вас есть проверка последнего выпущенного тега, ее создание, развертывание, возврат в ветку функции, продолжение. Это действительно делает его непригодным для использования.

По сути, нам нужна удаленная конфигурация для облачных функций.

@bezysoftware Я думаю, вам нужно использовать переменные среды (вместо конфигурации среды), вы можете пропустить уровень firebase и сделать это на облачной платформе Google, проверьте https://cloud.google.com/functions/docs/env- вар

Спасибо, что поделились! @laurenzlong
Я хотел импортировать из файла, поэтому использовал такую ​​команду.

firebase functions:config:set service_account="$(cat service-account.json)"

Я импортировал json-файл служебного аккаунта в Firebase Cloud Functions, потому что хотел использовать API управления пользователями Firebase Admin SDK.

Это не сработало

@ Md-Abdul-Halim-Rafi

функции firebase

Работал для меня, я вижу переменную конфигурации с firebase functions:config:get .
Это не сработало в первый раз, потому что я не был в папке проекта и не выбрал проект firebase для установки переменной конфигурации, чтобы выбрать проект firebase, используйте firebase use --add , CLI предложит вам список проектов на консоли firebase (при условии, что вы вошли в интерфейс командной строки с помощью firebase login )

@dnhyde

функции firebase

Кажется, это не сработает при использовании в вашем json файле любых других типов значений, кроме строк (например, логических или числовых):

{
   "test": {
        "hmm": true
    }
}

не работает с:

Error: HTTP Error: 400, Invalid value at 'variable.text' (TYPE_STRING), true

Мне кажется разумным, что я должен уметь:

firebase functions:config:get > config.json

а потом позже:

firebase functions:config:set < config.json

Просто имеет смысл, чтобы эти две команды дополняли друг друга.

Наличие конфигурации в файле позволяет мне контролировать ее версии и видеть, как она менялась с течением времени.

К сожалению, единственный способ, которым мы должны это сделать прямо сейчас (используя env=$(cat config.json) ), также приводит к нарушению моей способности иметь config.json в качестве фактических значений, поскольку я не могу обернуть их в { env: ... } .

Примечание для себя: именно здесь мне нужно начать запрос на включение функции:

Просто поделитесь своим ванильным JS-решением, которое работает в зависимости от платформы, на которой вы разрабатываете (Windows, MacOS, Linux):

Использование отдельных проектов для dev / test / prod.

/.firebaserc

{
  "projects": {
    "dev": "my-project-name-dev",
    "test": "my-project-name-test",
    "prod": "my-project-name-prod"
  }
}

Файлы конфигурации

JSON-файлы в папке /functions/config :

/functions/config/config.dev.json 
/functions/config/config.test.json 
/functions/config/config.prod.json 
/functions/config/config.SAMPLE.json <-- only file tracked in git

Example content:
{
    "google": {
        "key": "my-api-key",
        "storage_bucket": "firebase-storage-bucket"
    },
    "another_vendor": {
        "my_prop": "my value"
    },
    ...
}

/functions/set-config.js

const fs = require('fs');
const env = process.argv[2];

const configPath = `./config/config.${env}.json`;

if (!(configPath && fs.existsSync(configPath))) {
    return;
}

const collectConfigLines = (o, propPath, configLines) => {
    propPath = propPath || '';
    configLines = configLines || [];
    for (const key of Object.keys(o)) {
        const newPropPath = propPath + key;
        if (typeof o[key] === 'object') {
            collectConfigLines(o[key], newPropPath + '.', configLines);
        } else if (o[key] != null && o[key] !== '') {
            configLines.push(`${newPropPath}=${JSON.stringify(o[key])}`);
        }
    }
}

const config = require(configPath);
const configLines = [];
collectConfigLines(config, '', configLines);

const cp = require('child_process');
cp.execSync(`firebase -P ${env} functions:config:set ${configLines.join(' ')}`);

/functions/package.json

...
"scripts": {
    "config:set:dev": "node set-config dev",
    "config:set:test": "node set-config test",
    "config:set:prod": "node set-config prod",
    ...
},
...

Просто поделитесь своим ванильным JS-решением, которое работает в зависимости от платформы, на которой вы разрабатываете (Windows, MacOS, Linux):

Использование отдельных проектов для dev / test / prod.

/.firebaserc

{
  "projects": {
    "dev": "my-project-name-dev",
    "test": "my-project-name-test",
    "prod": "my-project-name-prod"
  }
}

Файлы конфигурации

JSON-файлы в папке /functions/config :

/functions/config/config.dev.json 
/functions/config/config.test.json 
/functions/config/config.prod.json 
/functions/config/config.SAMPLE.json <-- only file tracked in git

Example content:
{
    "google": {
        "key": "my-api-key",
        "storage_bucket": "firebase-storage-bucket"
    },
    "another_vendor": {
        "my_prop": "my value"
    },
    ...
}

/functions/set-config.js

const fs = require('fs');
const env = process.argv[2];

const configPath = `./config/config.${env}.json`;

if (!(configPath && fs.existsSync(configPath))) {
    return;
}

const collectConfigLines = (o, propPath, configLines) => {
    propPath = propPath || '';
    configLines = configLines || [];
    for (const key of Object.keys(o)) {
        const newPropPath = propPath + key;
        if (typeof o[key] === 'object') {
            collectConfigLines(o[key], newPropPath + '.', configLines);
        } else if (o[key] != null && o[key] !== '') {
            configLines.push(`${newPropPath}=${JSON.stringify(o[key])}`);
        }
    }
}

const config = require(configPath);
const configLines = [];
collectConfigLines(config, '', configLines);

const cp = require('child_process');
cp.execSync(`firebase -P ${env} functions:config:set ${configLines.join(' ')}`);

/functions/package.json

...
"scripts": {
    "config:set:dev": "node set-config dev",
    "config:set:test": "node set-config test",
    "config:set:prod": "node set-config prod",
    ...
},
...

Извините, но когда вы запускаете сценарий " config: set : dev"? Я не понимаю ... спасибо!

Была ли эта страница полезной?
0 / 5 - 0 рейтинги