0

I have an application design using flask with flask-sqlalchemy. In order to control database migrations as the models change I am using flask-migrate to wrap alembic and use within the flask-script management context.

I am trying to decide how to split the package distribution to achieve the following goals

  1. Minimal set of dependencies for the main application package
  2. Allow distribution of management scripts and test data for migrations and deployments perhaps using a secondary package depending on the main application module

The project structure is as follows

/
 tests/ #test data
 migrations/ #alembic root include env.py and alembic.ini
 myapp/ # application package
 setup.py
 manage.py
 wsgi.py

My manage.py looks like a lot the following. This is how I avoid any alembic or flask-migrate dependencies in the main application package, by attaching the Migrate object to the app in manage.py. This also allows me to control migration configurations in the same config file as the general flask/app configurations (as the config context is pushed by the manager and with Migrate.init_app)

from myapp import db, create_app
from myapp.database import database_manager #sub manager for creating/dropping db
from flask_migrate import Migrate, MigrateCommand

def _create_app(*args, **kwargs):
  app = create_app(*args, **kwargs)
  if migration is not None:
     migration.init_app(app)
  return app

manager = Manager(_create_app)
migration = Migrate(db = db)
manager.add_command('database', database_manager)
manager.add_command('migration', MigrateCommand)

if __name__ == "__main__":
    manager.run()

The application submanager myapp.database.database_manager enables such commands as python manage.py database create/drop/test_data which uses sqlalchemy to create tables and populate the table with test_data from tests/ directory, but does not hook in any migration scripts, and allows me to use python manage.py migration init/revision/migrate/... to execute flask-migrate/alembic commands using the application configuration context.

I am trying to distribute this application to deploy on our internal servers. There are two distribution use cases as they are currently being used

  1. Install new server

    • Install source distribution
    • Create new config file to reflect DB host etc.
    • Use manage.py -c /path/to/config to create database tables with database create
    • Point HTTP Server to wsgi.py
  2. Update existing server

    • Update source distribution
    • Use manage.py -c /path/to/server/config migration upgrade to pull up the databases using the current app context
    • Server continues to point to wsgi.py

I would like to move this distribution to wheels/packages so that I can automate deployment on our corp intranet, So what I'm seeing here is that I would like to split my package into the main package myapp with only Flask framework dependencies and wsgi entrypoint and myapp-manage which includes the manage.py , tests, and migrationsdirectory.

So in the perfect world, the application will be installed on the system with global configuration files, and a specific management user will have access to the management package to perform upgrades.

Right now I am angling towards splitting the distribution with setup-app.py and setup-manage.py to create two seperate packages from the same source distribution. Is there a more appropriate way to package migrations and management scripts with a flask application? I have dug through the docs and while its clear how to package a flask application, distribution strategies for management scripts and migrations is less clear.

crasic
  • 1,918
  • 2
  • 18
  • 29
  • Typically management scripts are distributed along with the application, not separately. What's the use case for having the management scripts as a separate package? – Miguel Grinberg Feb 16 '17 at 18:32
  • @Miguel in one word? **enterprise**, but really application robustness. The project is an internal manufacturing management site so the backend data is business critical. additional complication - the deployment target is a docker swarm on embedded devices. While some deployments are in controlled environment in our facilities, others are remote stations at suppliers and we would not like to expose migration details or let them inadvertently trigger database management functions during servicing or in case someone gets curious. An easy way to do that is cripple the application. – crasic Feb 16 '17 at 18:58
  • Additionally, how would one go about packaging the management scripts, put them in a sub-package? how does python handle root directory modules like 'manage.py' in a distribution? – crasic Feb 16 '17 at 19:01
  • What I fail to understand is how does separating management scripts help, since you have to install all those file to carry out an upgrade. I suppose you can install the management scripts, run the upgrade, then uninstall them, but it is pretty much the same if you have everything in one package and after the upgrade is complete you just delete the files you don't want your users to see. – Miguel Grinberg Feb 17 '17 at 05:54
  • The standard way to distribute executables such as manage.py in packages/wheels is to define them in the setup.py file as entry points. – Miguel Grinberg Feb 17 '17 at 05:56
  • @Miguel thank you for the hint, what I was missing was entrypoints. Seperating the management scripts in a docker deployment means I can run an upgrade script against a remote deployment while sitting at my pc, docker furnishes the network connection and live data. They never see it, and I can tightly couple management in the source project. – crasic Feb 17 '17 at 07:54

0 Answers0