diff --git a/backend/app.py b/backend/app.py index 242861b2e634df92473ba31e864fe96a503b80b5..ec18e9b6ebbf8f9fd90d8e82d73e5a7d2111a8c4 100644 --- a/backend/app.py +++ b/backend/app.py @@ -1,7 +1,7 @@ from flask import Flask, jsonify from flask_cors import CORS from flask_jwt_extended import JWTManager -from flask_migrate import Migrate +import flask_migrate from jsonschema.exceptions import ValidationError from werkzeug.exceptions import BadRequest @@ -35,6 +35,8 @@ from helpers import ( import cluster_config from config import * import logging +import migration_reset +import sys # Configure logging. from logging.config import dictConfig @@ -64,8 +66,20 @@ app.logger.setLevel(logging.INFO) app.logger.info("Starting dashboard backend.") cors = CORS(app) -Migrate(app, db) + db.init_app(app) +with app.app_context(): + # We have reset the alembic migration history at Stackspin version 2.2. + # This checks whether we need to prepare the database to follow that + # change. + migration_reset.reset() +flask_migrate.Migrate(app, db) +try: + with app.app_context(): + flask_migrate.upgrade() +except Exception as e: + app.logger.info(f"upgrade failed: {type(e)}: {e}") + sys.exit(2) # We need this app context in order to talk the database, which is managed by # flask-sqlalchemy, which assumes a flask app context. diff --git a/backend/migration_reset.py b/backend/migration_reset.py new file mode 100644 index 0000000000000000000000000000000000000000..4f674c75ecff4e31ccf744818978580270e4ef48 --- /dev/null +++ b/backend/migration_reset.py @@ -0,0 +1,34 @@ +from sqlalchemy import exc + +from database import db +import logging + +# We "reset" the alembic version history for Stackspin 2.2, to clean up our old +# mess of database migrations a bit, and in particular to make the transition +# easier to moving the source of truth for some of the data (list of apps) out +# of the database and into configmaps. This function deals with older clusters +# that have to be led through this transition. To determine if we need to do +# anything, we look at the `alembic_version` value in the database. If it's a +# legacy version, we delete the table so the alembic migration will view the +# database as "empty" and perform all new migrations on it. The new initial +# migration will have to handle that case specially, by checking if any tables +# already exist, and not do anything in that case. +def reset(): + logging.info("Checking if alembic version needs to be reset.") + version = None + try: + result = db.session.execute("select version_num from alembic_version") + for row in result: + version = row[0] + except exc.ProgrammingError: + # We assume this means the alembic_version table doesn't exist, which + # is expected for new clusters. + pass + logging.info(f"alembic version: {version}") + legacy_versions = ["fc0892d07771", "3fa0c38ea1ac", "e08df0bef76f", "b514cca2d47b", "5f462d2d9d25", "27761560bbcb"] + if version in legacy_versions: + logging.info("This is an old version: resetting.") + db.session.execute("drop table alembic_version") + else: + logging.info("This is not a known legacy version: not resetting.") + diff --git a/backend/migrations/alembic.ini b/backend/migrations/alembic.ini index ec9d45c26a6bb54e833fd4e6ce2de29343894f4b..ef355cdd0bc77377516a78e5f891f20b8573b403 100644 --- a/backend/migrations/alembic.ini +++ b/backend/migrations/alembic.ini @@ -8,43 +8,3 @@ # 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 diff --git a/backend/migrations/env.py b/backend/migrations/env.py index 68feded2a040005310d770ac7136b2e4ff8a6312..2a7628b80babbf6b5a2777efe7e02c5c115c391c 100644 --- a/backend/migrations/env.py +++ b/backend/migrations/env.py @@ -13,7 +13,9 @@ config = context.config # Interpret the config file for Python logging. # This line sets up loggers basically. -fileConfig(config.config_file_name) +# We commented this out, because we want to configure logging in the app +# itself, not here. +# fileConfig(config.config_file_name) logger = logging.getLogger('alembic.env') # add your model's MetaData object here