web-dev-qa-db-fra.com

Est-il possible de stocker la chaîne de connexion alembic en dehors de alembic.ini?

J'utilise Alembic avec SQL Alchemy. Avec SQL Alchemy, j'ai tendance à suivre un schéma selon lequel je ne stocke pas la chaîne de connexion avec le code versionné. Au lieu de cela, j'ai le fichier secret.py qui contient des informations confidentielles. Je jette ce nom de fichier dans mon .gitignore pour qu'il ne finisse pas sur GitHub.

Ce modèle fonctionne bien, mais je commence maintenant à utiliser Alembic pour les migrations. Il semble que je ne peux pas cacher la chaîne de connexion. Dans alembic.ini, placez plutôt la chaîne de connexion en tant que paramètre de configuration :

# the 'revision' command, regardless of autogenerate
# revision_environment = false

sqlalchemy.url = driver://user:pass@localhost/dbname

# Logging configuration
[loggers]
keys = root,sqlalchemy,alembi

Je crains de valider accidentellement un fichier contenant les informations de nom d'utilisateur/mot de passe pour ma base de données. Je préférerais stocker cette chaîne de connexion à un seul endroit et éviter le risque de la commettre accidentellement au contrôle de version.

Quelles sont mes options?

34
Doug T.

J'ai eu le même problème hier et j'ai trouvé la solution suivante qui fonctionne: Je procède comme suit dans alembic/env.py:

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# this will overwrite the ini-file sqlalchemy.url path
# with the path given in the config of the main code
import config as ems_config
config.set_main_option('sqlalchemy.url', ems_config.config.get('sql', 'database'))

ems_config est un module externe qui contient mes données de configuration.

config.set_main_option(...) écrase essentiellement la clé sqlalchemy.url dans la section [alembic] du fichier alembic.ini. Dans ma configuration, je le laisse simplement noir.

35
Tammo Heeren

La documentation Alembic suggère d'utiliser create_engine avec l'URL de la base de données (au lieu de de modifier sqlalchemy.url dans le code ).

Vous devez également modifier run_migrations_offline pour utiliser la nouvelle URL. Allan Simon a un exemple sur son blog, mais en résumé, modifiez env.py pour:

  1. Fournissez une fonction partagée pour obtenir l’URL d’une manière ou d’une autre (ici elle provient de la ligne de commande):

    def get_url():
        url = context.get_x_argument(as_dictionary=True).get('url')
        assert url, "Database URL must be specified on command line with -x url=<DB_URL>"
        return url
    
  2. Utilisez l'URL en mode hors connexion:

    def run_migrations_offline():
        ...
        url = get_url()
        context.configure(
            url=url, target_metadata=target_metadata, literal_binds=True)
        ...
    
  3. Utilisez l'URL en mode en ligne en utilisant create_engine au lieu de engine_from_config:

    def run_migrations_online():
        ...
        connectable = create_engine(get_url())
        with connectable.connect() as connection:
        ...
    
11
danio

Donc, ce qui semble fonctionner, c’est la réimplémentation de la création de moteur dans env.py, qui est apparemment un endroit approprié pour effectuer ce type de personnalisation. Au lieu d’utiliser la chaîne sqlalchemy connect dans l’ini:

engine = engine_from_config(
            config.get_section(config.config_ini_section),
            prefix='sqlalchemy.',
           poolclass=pool.NullPool)

Vous pouvez remplacer et spécifier votre propre configuration de moteur:

import store
engine = store.engine

En effet, les docs semblent impliquer c’est ok:

sqlalchemy.url - Une URL permettant de se connecter à la base de données via SQLAlchemy. Cette clé n'est en fait référencée que dans le fichier env.py spécifique à la configuration «générique»; un fichier qui peut être personnalisé par le développeur. Une configuration multiple de base de données peut ici répondre à plusieurs clés ou faire référence à d'autres sections du fichier.

8
Doug T.

Je cherchais depuis un moment comment gérer cela pour plusieurs bases de données

Voici ce que j'ai fait. J'ai deux bases de données: logs et ohlc

D'après le doc , J'ai configuré l'alambic comme ça

alembic init --template multidb

alembic.ini

databases = logs, ohlc
[logs]
sqlalchemy.url = postgresql://botcrypto:botcrypto@localhost/logs
[ohlc]
sqlalchemy.url = postgresql://botcrypto:botcrypto@localhost/ohlc

env.py

[...]
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')

# overwrite alembic.ini db urls from the config file
settings_path = os.environ.get('SETTINGS')
if settings_path:
    with open(settings_path) as fd:
        settings = conf.load(fd, context=os.environ) # loads the config.yml
    config.set_section_option("ohlc", "sqlalchemy.url", settings["databases"]["ohlc"])
    config.set_section_option("logs", "sqlalchemy.url", settings["databases"]["logs"])
else:
    logger.warning('Environment variable SETTINGS missing - use default alembic.ini configuration')
[...]

config.yml

databases:
    logs: postgresql://botcrypto:[email protected]:5432/logs
    ohlc: postgresql://botcrypto:[email protected]:5432/ohlc

usage

SETTINGS=config.yml alembic upgrade head

J'espère que ça peut aider!

0

Comme Doug T. l'a dit vous pouvez éditer env.py pour fournir une URL depuis un fichier autre que le fichier ini. Au lieu de créer un nouveau moteur, vous pouvez passer un argument url supplémentaire à la fonction engine_from_config (les kwargs sont ensuite fusionnés avec des options extraites du fichier ini). Dans ce cas, vous pourriez par exemple stocker le mot de passe crypté dans un fichier ini et le décrypter au moment de l'exécution à l'aide de la phrase secrète stockée dans la variable ENV.

connectable = engine_from_config(                 
    config.get_section(config.config_ini_section),
    prefix='sqlalchemy.',                         
    poolclass=pool.NullPool,                      
    url=some_decrypted_endpoint)                                   
0
Bartoszer

Une autre solution consiste à créer un modèle de fichier alembic.ini.dist et à le suivre à l'aide de votre code mis à jour, tout en ignorant alembic.ini dans votre VCS.

N'ajoutez aucune information confidentielle dans alembic.ini.dist:

sqlalchemy.url = ...

Lorsque vous déployez votre code sur une plate-forme, copiez alembic.ini.dist dans alembic.ini (celui-ci ne sera pas suivi par votre VCS) et modifiez alembic.ini avec les informations d'identification de la plate-forme.

0
rkz_io