-
Notifications
You must be signed in to change notification settings - Fork 3
Develop #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Develop #80
Changes from 7 commits
508357c
016038a
9f09b78
385434f
49b8e8c
d3689b4
cdaaf81
f42c480
9f66cb9
6cf92c1
f70a357
33d68ed
5c16cc3
9d7a954
2033d8d
4a1c750
cd8dc5d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,6 @@ | ||
| config.py | ||
| instance_config_override.py | ||
| run.py | ||
| migrations/ | ||
|
|
||
| # PyPi | ||
| .pypirc | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,39 +1,55 @@ | ||
| """ | ||
| Initialize the ExaFS database using Alembic migrations. | ||
|
|
||
| from flask import Flask | ||
| from flowapp import db | ||
| from flowapp.models import * | ||
| Usage: | ||
| python db-init.py # Create database from baseline migration | ||
| python db-init.py --reset # Drop all tables first, then recreate (DESTRUCTIVE) | ||
| """ | ||
|
|
||
| import config | ||
| import sys | ||
| from os import environ | ||
|
|
||
| from flask_migrate import upgrade | ||
| from flowapp import create_app, db | ||
|
|
||
| import config | ||
|
|
||
| def create_app(): | ||
| app = Flask('FlowSpecDB init') | ||
| # Configurations | ||
| try: | ||
| env = environ['USERNAME'] | ||
| except KeyError as e: | ||
| env = 'Production' | ||
|
|
||
| if env == 'albert': | ||
| print("DEVEL") | ||
| app.config.from_object(config.DevelopmentConfig) | ||
| def init_db(reset=False): | ||
| exafs_env = environ.get("EXAFS_ENV", "Production").lower() | ||
| if exafs_env in ("devel", "development"): | ||
| app = create_app(config.DevelopmentConfig) | ||
| else: | ||
| print("PRODUCTION") | ||
| app.config.from_object(config.ProductionConfig) | ||
| app = create_app(config.ProductionConfig) | ||
|
|
||
| db.init_app(app) | ||
|
|
||
| with app.app_context(): | ||
| print("#: cleaning database") | ||
| db.reflect() | ||
| db.drop_all() | ||
| print("#: creating tables") | ||
| db.create_all() | ||
|
|
||
|
|
||
| return app | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| create_app().app_context().push() | ||
| if reset: | ||
| print("#: WARNING - dropping all tables") | ||
| db.reflect() | ||
| db.drop_all() | ||
| # Also remove alembic_version if it exists | ||
| from sqlalchemy import text | ||
|
|
||
| try: | ||
| db.session.execute(text("DROP TABLE IF EXISTS alembic_version")) | ||
| db.session.commit() | ||
| except Exception: | ||
| db.session.rollback() | ||
|
|
||
| print("#: running migrations (flask db upgrade)") | ||
| upgrade() | ||
| print("#: database initialized successfully") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| reset = "--reset" in sys.argv | ||
| if reset: | ||
| print("Reset mode: all existing data will be DESTROYED.") | ||
| confirm = input("Are you sure? (yes/no): ") | ||
| if confirm.lower() != "yes": | ||
| print("Aborted.") | ||
| sys.exit(0) | ||
|
|
||
| init_db(reset=reset) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,35 +1,108 @@ | ||
| # How to Upgrade the Database | ||
| # Database Migrations | ||
|
|
||
| ## General Guidelines | ||
| Migrations can be inconsistent. To avoid issues, we removed migrations from git repostory. To start the migration on your server, it is recomended reset the migration state on the server and run the migration based on the updated database models when switching application versions via Git. | ||
| ExaFS uses [Flask-Migrate](https://flask-migrate.readthedocs.io/) (Alembic) for database schema management. Migration files are shipped inside the `flowapp` package (`flowapp/migrations/`) and are found automatically — no `flask db init` is needed. | ||
|
|
||
| ## New Installation | ||
|
|
||
| For a fresh database, run the migrations to create all tables and seed data: | ||
|
|
||
| ```bash | ||
| rm -rf migrations/ | ||
| flask db upgrade | ||
| ``` | ||
|
|
||
| ```SQL | ||
| DROP TABLE alembic_version; | ||
| Or use the init script: | ||
|
|
||
| ```bash | ||
| python db-init.py | ||
| ``` | ||
|
|
||
| ## Upgrading Between Versions | ||
|
|
||
| When upgrading ExaFS to a new version, apply any new migrations: | ||
|
|
||
| ```bash | ||
| flask db upgrade | ||
| ``` | ||
|
|
||
| This will apply only the migrations that haven't been applied yet. | ||
|
|
||
| ## Existing Installation (One-Time Setup) | ||
|
|
||
| If you already have a running ExaFS database from any previous version, the baseline migration is idempotent — it will create missing tables, add missing columns, and skip anything that already exists. | ||
|
|
||
| ### Deployments that used `flask db init` (self-managed migrations) | ||
|
|
||
| Some deployments previously ran `flask db init` to create a local `migrations/` directory and auto-generated migration files. Starting with v1.2.2, migration files are tracked in git and shipped with the project. To switch to the official migrations: | ||
|
|
||
| 1. **Delete the local migrations directory** created by `flask db init`: | ||
| ```bash | ||
| rm -rf migrations/ | ||
| ``` | ||
| Migrations are now bundled inside the `flowapp` pip package — no local directory needed. | ||
|
|
||
| 2. **Clear the old alembic_version** and **stamp the baseline** to register with the official migration track (your schema is already up to date): | ||
| ```sql | ||
| DELETE FROM alembic_version; | ||
| ``` | ||
| ```bash | ||
| flask db stamp 001_baseline | ||
| ``` | ||
|
|
||
| 3. From now on, just run `flask db upgrade` when updating ExaFS. | ||
|
|
||
| ### Deployments without any migration tracking | ||
|
|
||
| If your database has an `alembic_version` table from a previous migration setup but no local `migrations/` directory, clear it first: | ||
|
|
||
| ```sql | ||
| DELETE FROM alembic_version; | ||
| ``` | ||
|
|
||
| Then run the upgrade: | ||
|
|
||
| ```bash | ||
| flask db init | ||
| flask db migrate -m "Initial migration based on current DB state" | ||
| flask db upgrade | ||
| ``` | ||
|
|
||
| ## Steps for Upgrading to v1.0.x | ||
| Limits for number of rules were introduced. Some database engines (Mariadb 10.x for example) have issue to set Non Null foreigin key to 0 and automatic migrations fail. The solution may be in diferent version (Mariadb 11.x works fine), or to set limits in db manually later. | ||
| The baseline migration will inspect your database and bring it up to the current schema without affecting existing data. | ||
|
|
||
| To set the limit to 0 for existing organizations run | ||
| ## Upgrading from v0.x to v1.0+ | ||
|
|
||
| ```SQL | ||
| UPDATE organization | ||
| SET limit_flowspec4 = 0, limit_flowspec6 = 0, limit_rtbh = 0 | ||
| WHERE limit_flowspec4 IS NULL OR limit_flowspec6 IS NULL OR limit_rtbh IS NULL; | ||
| If you are upgrading from a pre-1.0 version, the baseline migration will add the missing `org_id` columns and organization limit columns automatically. However, existing rules still need to be linked to organizations. An optional helper script is provided for this: | ||
|
|
||
| ```bash | ||
| python scripts/migrate_v0x_to_v1.py | ||
| ``` | ||
|
|
||
| In all cases we need later assign rules to organizations. There's an admin endpoint for this: | ||
| This script: | ||
| 1. Sets NULL organization limits to 0 | ||
| 2. Assigns rules with `org_id=0` to the user's organization | ||
| 3. Reports users with multiple organizations that need manual assignment | ||
|
|
||
| Feel free to contact jiri.vrany@cesnet.cz if you need help with the migration. | ||
|
Comment on lines
+75
to
+88
|
||
|
|
||
| ## Creating New Migrations | ||
|
|
||
| When you modify a database model, create a new migration: | ||
|
|
||
| ```bash | ||
| flask db migrate -m "Description of changes" | ||
| ``` | ||
|
|
||
| `https://yourexafs.url/admin/set-org-if-zero` | ||
| Review the generated file in `flowapp/migrations/versions/`, then apply it: | ||
|
|
||
| ```bash | ||
| flask db upgrade | ||
| ``` | ||
|
|
||
| Commit the migration file to git so other deployments can apply it. | ||
|
|
||
| ## Development Reset | ||
|
|
||
| To completely reset the database during development: | ||
|
|
||
| ```bash | ||
| python db-init.py --reset | ||
| ``` | ||
|
|
||
| Or you can start with clean database and manually migrate data by SQL dump later. Feel free to contact jiri.vrany@cesnet.cz if you need help with the DB migration to 1.0.x. | ||
| This drops all tables and recreates them from scratch. **Do not use in production.** | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Single-database configuration for Flask. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| # A generic, single database configuration. | ||
|
|
||
| [alembic] | ||
| # template used to generate migration files | ||
| # file_template = %%(rev)s_%%(slug)s | ||
|
|
||
| # set to 'true' to run the environment during | ||
| # the 'revision' command, regardless of autogenerate | ||
| # revision_environment = false | ||
|
|
||
|
|
||
| # Logging configuration | ||
| [loggers] | ||
| keys = root,sqlalchemy,alembic,flask_migrate | ||
|
|
||
| [handlers] | ||
| keys = console | ||
|
|
||
| [formatters] | ||
| keys = generic | ||
|
|
||
| [logger_root] | ||
| level = WARN | ||
| handlers = console | ||
| qualname = | ||
|
|
||
| [logger_sqlalchemy] | ||
| level = WARN | ||
| handlers = | ||
| qualname = sqlalchemy.engine | ||
|
|
||
| [logger_alembic] | ||
| level = INFO | ||
| handlers = | ||
| qualname = alembic | ||
|
|
||
| [logger_flask_migrate] | ||
| level = INFO | ||
| handlers = | ||
| qualname = flask_migrate | ||
|
|
||
| [handler_console] | ||
| class = StreamHandler | ||
| args = (sys.stderr,) | ||
| level = NOTSET | ||
| formatter = generic | ||
|
|
||
| [formatter_generic] | ||
| format = %(levelname)-5.5s [%(name)s] %(message)s | ||
| datefmt = %H:%M:%S |
Uh oh!
There was an error while loading. Please reload this page.