Firebase-tools: Accepter le fichier JSON pour les fonctions : config : set

Créé le 20 juil. 2017  ·  37Commentaires  ·  Source: firebase/firebase-tools

Actuellement, il est possible d'obtenir l'ensemble de la configuration des fonctions sous forme de fichier JSON en utilisant firebase functions:config:get , mais nous devons insérer manuellement chaque variable lors de l'utilisation de la commande firebase functions:config:set , ce qui la rend pratiquement inutilisable lorsque l'on travaille sur environnements différents.

Idéalement, nous devrions être capables de faire :

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

Commentaire le plus utile

Merci pour votre partage ! @laurenzlong
Je voulais importer à partir d'un fichier, j'ai donc utilisé une commande comme celle-ci.

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

J'ai importé un fichier json de compte de service dans Firebase Cloud Functions, car je souhaitais utiliser l'API de gestion des utilisateurs de Firebase Admin SDK.

Tous les 37 commentaires

Je suis d'accord avec @jpreynat , nous config:set dans nos scripts de déploiement personnalisés avec un config.json serait une fonctionnalité intéressante à voir ajoutée.
Existe-t-il des solutions de contournement en ce moment, peut-être une canalisation dans la configuration ?

On dirait que vous essayez de répliquer la configuration sur plusieurs projets. Est-ce que firebase functions:config:clone fonctionnerait pour vous ?

Pour donner un peu de contexte, nous nous sommes intentionnellement éloignés de la configuration basée sur des fichiers car nous pensons qu'elle encourage les mauvaises pratiques (à savoir, conserver un fichier plein de secrets stockés avec votre code, potentiellement même archivés dans votre référentiel source).

Que penseriez-vous d'un moyen (mécanique à déterminer) pour déclarer les variables de configuration "requises" - et si vous essayiez de déployer sans la configuration requise dans le projet en cours, une erreur se produirait avant que quoi que ce soit ne soit modifié. Cela résoudrait-il vos principales préoccupations? Si non, pourquoi avoir un fichier vous est-il particulièrement utile ?

@mbleigh C'est exactement ce que je ne savais pas que je voulais. Bonne idée!
Probablement une donnée/ce que vous entendiez par « Mécanique à déterminer », mais : Définir la structure des clés/configuration dans un fichier de notre projet plutôt qu'à distance, afin qu'il passe par le processus de révision git/PR comme tout le reste.
@jpreynat Désolé pour le problème de piratage

@laurenzlong Merci pour les conseils, mais nous
Notre principale préoccupation est de mettre à jour différentes configurations de projets en fonction de notre étape de déploiement.
Donc, fondamentalement, nous avons un fichier de configuration par environnement (dev, staging et prod) et définissons respectivement la configuration Firebase (pour les PR, appuyez sur le maître et les balises).

@mbleigh Merci pour l'information.
Cependant, nous ne savons pas exactement comment nous pouvons stocker tous ces environnements autrement qu'en utilisant des fichiers de configuration.
Ils sont actuellement formatés en JSON pour simplifier la lecture, mais nous pensons les formater en paires clé/valeur pour les transmettre directement à la commande functions:config:set .
Je suis d'accord avec vous pour dire que ce n'est pas plus sûr que de transmettre un fichier JSON.
Avez-vous des recommandations sur la façon dont nous pourrions stocker nos variables d'environnement pour différentes étapes autres que l'utilisation de fichiers ?

@ahaverty Pas de soucis, je suis content que cela puisse être débattu ici.

@jpreynat lorsque vous exécutez functions:config:set il est stocké avec le projet en cours. Si vous utilisez firebase use pour basculer entre les projets, votre configuration sera persistante. Vous pouvez donc exécuter set une fois par projet et il sera toujours là. Cela devrait résoudre le problème de "configuration différente pour différents environnements", alors peut-être que je ne comprends pas le vrai problème ?

@jpreynat Je vais fermer ce problème pour le moment, mais veuillez rouvrir si Michael et moi avons mal compris votre demande.

@laurenzlong @mbleigh Désolé de ne pas avoir répondu rapidement sur ce fil.
Nous avons trouvé une solution de contournement à ce problème pour le moment, mais voici un contexte pour clarifier ma demande :

Nous déployons notre application en utilisant Travis (notez que ce serait génial avec n'importe quel CI ou même localement). Étant donné que nous déployons notre application à différentes étapes en fonction de la branche et de la balise, ce serait formidable de pouvoir utiliser un fichier JSON différent en fonction de l'environnement.
Par exemple, cela permettrait de faire soit firebase config:set -f staging.json soit firebase config:set -f prod.json fonction de cette condition.
Notre solution de contournement consistait à utiliser firebase comme module de nœud, mais nous devons toujours aligner notre configuration JSON, qui est sujette aux erreurs.

Hey @jpreynat, je suis toujours un peu confus par ta réponse. Une fois que vous avez défini la configuration une fois, elle y reste toujours, même d'un déploiement à l'autre, à moins que vous ne désactiviez explicitement les valeurs de configuration en exécutant firebase functions:config :unset. Il n'est donc pas nécessaire que cela fasse partie du processus d'EC.

Quelqu'un peut-il rouvrir ça ? %) @jpreynat @mbleigh C'est vraiment une des choses qui manque. Atm J'ai près de 15 variables de configuration (et d'autres à venir) et ce sera très pratique si functions:config:set peut accepter JSON d'une manière ou d'une autre.

Gros vote de notre part pour la suggestion de @mbleigh sur "déclarer les variables de configuration "requises" - et si vous essayiez de déployer sans la configuration requise dans le projet en cours, une erreur se produirait avant que quoi que ce soit ne soit modifié."
Devenir un problème pour nous aussi, mais cela résoudrait tous nos problèmes et s'intégrerait parfaitement dans le processus de contrôle de version/révision 👍

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

Hey @yaronyosef Vous pouvez directement fournir JSON à la commande firebase functions:config :set, c'est juste que vous devez le formater d'une manière appropriée à votre plate-forme. Pour Linux, les éléments suivants devraient fonctionner :

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

Merci pour votre partage ! @laurenzlong
Je voulais importer à partir d'un fichier, j'ai donc utilisé une commande comme celle-ci.

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

J'ai importé un fichier json de compte de service dans Firebase Cloud Functions, car je souhaitais utiliser l'API de gestion des utilisateurs de Firebase Admin SDK.

Cas d'utilisation sympa ! Merci d'avoir partagé!

Nous préférerions également suivre les configurations non secrètes via Git, où les fichiers de configuration d'exécution JSON validés (pour plusieurs environnements) feront autorité et l'environnement CI appliquera alors functions:config:set partir du fichier correspondant à un environnement particulier (et chaque environnement correspond à un projet Firebase distinct).

Si vous conservez les configurations dans git, il est trivial de les lire dans l'exécution de vos fonctions. Mettez-les simplement à configs/<project_id>.json et ensuite :

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

La configuration d'exécution utilisée par Firebase est spécialement conçue pour éviter que la configuration soit vérifiée dans git, car (en particulier avec les secrets), nous avons constaté qu'il s'agissait d'un modèle qui cause plus de problèmes qu'il n'en résout.

C'est vrai, même si nous n'utilisons plus du tout l'API Config à cette fin. Il peut être avantageux de passer par l'API Config pour stocker les valeurs sensibles (ce qui semble être un cas d'utilisation approprié, basé sur les documents Firebase) et de charger les valeurs contrôlées par la source et non suivies de la même manière exacte (c'est-à-dire via config() fourni par firebase-functions ).

Pour le moment, j'utilise le one-liner suivant pour alimenter l'ensemble de .runtimeconfig à functions:config:set :

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

FIREBASE_ENV est le nom de l'environnement utilisé dans le déploiement (par exemple dev ). Ce serait bien de pouvoir raccourcir cela davantage, par exemple

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

En fin de compte, même cela peut ne pas être nécessaire si l'API Config activait des pistes d'audit simples à utiliser de toutes les modifications (corrigez-moi si c'est déjà le cas, j'aimerais explorer cela).

Alors comment cela se passe-t-il ? ??

J'adorerais que la suggestion de @mbleigh soit toujours mise en œuvre ! Nous avons constamment des problèmes en oubliant de définir des configurations sur nos cibles non-dev

Merci pour la bosse du fil. Rien à signaler pour l'instant, mais j'en reparlerai lors de nos réunions de planification pour voir si nous pouvons commencer à progresser.

Je valide ma configuration avec un fichier de schéma JSON pour m'assurer qu'il contient toutes les valeurs que j'attends. Cette validation fait partie de mon pipeline CI et empêche le déploiement en cas d'échec. Si comme moi vous utilisez TypeScript pour écrire vos fonctions, vous pouvez générer le schéma JSON à partir de vos types.

Cela fonctionne très bien, avec la limitation que la configuration des fonctions n'accepte que des chaînes, de sorte que le schéma ne peut pas valider qu'une valeur de configuration est un nombre. Pour les booléens, c'est OK car je peux utiliser une énumération avec "true" et "false" comme seules valeurs valides.

Voir ma configuration CircleCI et ce billet de blog pour référence.

@hgwood merci pour le partage ! Nous allons certainement ajouter cela à notre CI aussi.

Je voulais juste laisser ma solution à ce "problème", et mes réflexions sur la discussion :

  1. Je comprends que les valeurs secrètes/sensibles ne doivent PAS être stockées dans le dépôt. Ma solution ne concerne que les valeurs non secrètes. Les valeurs secrètes sont définies manuellement, mais un moyen de marquer les valeurs de configuration comme requis serait merveilleux pour ces valeurs secrètes.
  2. Je pense que c'est plus important que certains semblent le penser. C'est un PITA de devoir définir manuellement des valeurs de configuration individuelles pour différents projets d'environnement de déploiement, et de ne pas pouvoir les visualiser/comparer simultanément facilement. La définition des configurations dans les fichiers rend le processus BEAUCOUP moins compliqué.
  3. Je pense que l'ajout d'un éditeur de configuration de fonctions à la console Web améliorerait beaucoup cela, mais ce serait vraiment bien s'il y avait un moyen de visualiser simultanément les configurations de plusieurs projets, afin que vous puissiez facilement comparer les configurations pour différents environnements de déploiement.
  4. Je dis depuis toujours que firebase doit permettre de définir des environnements au sein d'un seul projet, vous n'avez donc pas besoin de plusieurs projets à utiliser comme environnements de déploiement. Si cela existait, il serait très facile de visualiser simultanément les configurations de plusieurs environnements au sein d'un même projet.
  5. Ma solution a probablement des problèmes, ne faites pas confiance à mon code mot à mot, mais j'aime le concept général.

Ma solution

J'utilise des fichiers de configuration yaml en cascade, ce qui est utile pour les valeurs par défaut et les valeurs qui s'appliquent à toutes les configurations, quel que soit l'environnement de déploiement.

./config/default.yml

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

./config/dev.yml (fichiers de configuration similaires pour d'autres environnements de déploiement)

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

Ensuite, j'ai écrit un petit script de nœud qui charge la configuration résolue et renvoie une liste délimitée par des espaces de paires clé=val

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(' '))

Pendant le déploiement de CI, j'utilise ce script shell bash pour obtenir les paires key=val et les définir avec 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 J'aime votre solution cat , mais n'avez-vous pas rencontré d'erreur Precondition check failed en essayant de télécharger votre fichier de certificat ?

Nous avons fini par utiliser Deployment Manager pour ces raisons.

Nous définissons toute la configuration via "config Yaml" pour DM. Ensuite, DM crée les configurations et variables d'exécution appropriées, et firebase deploy récupère et définit leurs valeurs au moment du déploiement sans avoir à utiliser du tout firebase config:set . Cela nous permet également de configurer d'autres ressources (par exemple des buckets et leur contrôle d'accès) et de définir leurs valeurs dans RC sans avoir à les fournir en externe au modèle. De plus, cela nous permet d'utiliser la configuration camelCase et les noms de variables.

La seule fois où nous définissons une valeur en externe, c'est lorsque nous devons transmettre une clé de compte de service (cryptée) via la configuration d'exécution, car DM ne peut pas crypter les valeurs de manière sécurisée. Mais nous utilisons toujours gcloud beta runtime-config configs variables set pour cela (après le déploiement DM et avant firebase deploy ) et non firebase config:set , car le premier accepte stdout de KMS.

Je voulais juste ajouter - en lisant ceci, il semble que certaines personnes ont raté un point crucial qui conduit à une certaine confusion. Ce serait vraiment utile si cela était également clarifié dans la documentation.

Fondamentalement, le functions.config() persiste entre les _déploiements_, mais peut AUSSI être défini séparément entre différents projets Firebase !

Cela signifie que pour les environnements de développement, de développement et de production, vous devez configurer plusieurs projets Firebase identiques (plutôt que d'utiliser un hébergement multi-sites ou un déploiement sur le MÊME projet... 👎 ) qui conservent chacun leurs propres variables d'environnement - différentes - .

Une fois que vous avez défini des alias (ou simplement basculé entre des projets avec firebase use ), vous pouvez déployer le même référentiel sur plusieurs projets Firebase distincts. C'est ainsi que vous configurez un environnement de développement, une mise en scène et une production - en tant que projets Firebase distincts.

Ensuite, vous pouvez définir des configurations d'environnement distinctes pour chacun, comme ceci :
firebase -P dev config:set - définir des variables pour votre environnement de développement
firebase -P prod config:set - définissez des variables pour votre environnement de production...

Ensuite, vous pouvez déployer deux fois le même référentiel, comme ceci :
firebase deploy -P dev
firebase deploy -P prod
et ils seront tous les deux déployés dans leur projet Firebase respectif et contiendront leur propre configuration d'environnement distincte qui persistera entre les déploiements.

Oui, c'est comme ça qu'on fait aussi. Projets séparés pour dev/test/prod.

Je partage juste ma solution vanilla JS qui fonctionne en fonction de la plate-forme sur laquelle vous développez (Windows, MacOS, Linux) :

Utilisation de projets séparés pour dev/test/prod.

/.firebaserc

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

Fichiers de configuration

Fichiers JSON dans le dossier /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",
    ...
},
...

Si quelqu'un cherche toujours, il y a la méthode utilisée dans cet article moyen https://medium.com/indielayer/deploying-environment-variables-with-firebase-cloud-functions-680779413484. Sauvé ma vie.

Ce qui me manque personnellement, c'est la possibilité de définir une variable de configuration sans effectuer de déploiement. Nous avons un pipeline CICD qui effectue le déploiement dans nos différents environnements et nous ne voulons pas qu'un développeur construise le code localement et le déploie, surtout pas en production. C'est ainsi que les choses se brisent.

De plus, si nous voulons modifier une variable existante plus tard, avec une fonctionnalité en cours de développement, vous devez maintenant récupérer la dernière balise publiée, la construire, la déployer, la récupérer dans votre branche de fonctionnalité, continuer. Cela rend vraiment cela inutilisable.

Essentiellement, nous voudrions une configuration à distance pour les fonctions cloud

@bezysoftware Je pense que vous devez utiliser des variables d'environnement (au lieu de la configuration de l'environnement), vous pouvez ignorer la couche firebase et le faire sur la plate-forme google cloud, consultez https://cloud.google.com/functions/docs/env- var

Merci pour votre partage ! @laurenzlong
Je voulais importer à partir d'un fichier, j'ai donc utilisé une commande comme celle-ci.

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

J'ai importé un fichier json de compte de service dans Firebase Cloud Functions, car je souhaitais utiliser l'API de gestion des utilisateurs de Firebase Admin SDK.

ça n'a pas marché

@Md-Abdul-Halim-Rafi

fonctions firebase

A fonctionné pour moi, je peux voir la config var avec firebase functions:config:get .
Cela n'a pas fonctionné la première fois car je n'étais pas dans le dossier du projet et je n'ai pas sélectionné le projet firebase sur lequel définir la variable de configuration, pour sélectionner le projet firebase, utilisez firebase use --add , la CLI vous demandera le liste des projets sur votre console firebase (en supposant que vous êtes connecté à la CLI avec firebase login )

@dnhyde

fonctions firebase

Il semble que cela ne fonctionnera pas si vous utilisez dans votre fichier json d'autres types de valeurs, à l'exception des chaînes (par exemple, booléen ou numérique):

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

échoue avec :

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

Il me semble raisonnable de pouvoir faire :

firebase functions:config:get > config.json

puis plus tard :

firebase functions:config:set < config.json

Il est logique que ces deux commandes soient complémentaires.

Avoir la configuration dans un fichier me permet de la contrôler en version et de voir comment elle a changé au fil du temps.

Il est regrettable que la seule façon dont nous ayons pour le moment d'accomplir cela (en utilisant env=$(cat config.json) ) ait également pour effet de briser ma capacité à faire en sorte que config.json soit les valeurs réelles car je ne peux pas les envelopper dans { env: ... } .

Remarque pour moi-même : c'est ici que je dois commencer pour une demande d'extraction de fonctionnalité : https://github.com/firebase/firebase-tools/blob/b17611a4ff0d36e157ed06a24f6c81d4e146d9e2/src/functionsConfig.js#L142

Je partage juste ma solution vanilla JS qui fonctionne en fonction de la plate-forme sur laquelle vous développez (Windows, MacOS, Linux) :

Utilisation de projets séparés pour dev/test/prod.

/.firebaserc

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

Fichiers de configuration

Fichiers JSON dans le dossier /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",
    ...
},
...

Je partage juste ma solution vanilla JS qui fonctionne en fonction de la plate-forme sur laquelle vous développez (Windows, MacOS, Linux) :

Utilisation de projets séparés pour dev/test/prod.

/.firebaserc

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

Fichiers de configuration

Fichiers JSON dans le dossier /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",
    ...
},
...

Désolé mais quand exécutez-vous le script " config:set :dev" ? Je ne comprends pas... merci !

Cette page vous a été utile?
0 / 5 - 0 notes