You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A deployment hotfix accidentally introduced Alembic onto several nodes WITHOUT correctly stamping them.
This was not detected until after several revisions had been committed to the branch. These nodes were each at varying revisions, but all thought they were at BASE. None could upgrade to HEAD, as they already had the migrations.
This script was developed to update the nodes. It does the following:
archives the sqlite3 database to a backup file
iterates the revision history in order:
stamps the revision, attempts to upgrade to HEAD
on failure, the database is restored from the backup, and the next revision is tried
on success, we're done!
This might work with your sqlite3 installs. This could be adapted to other backends.
This assumes an upgrade from no stamp has failed; this does not detect an existing revision stamp in the database.
This uses psutil; it could be rewritten to use subprocess. I just prefer psutil.
# stdlibimportosimportshutilimportsubprocessimportsysfromtypingimportOptional# pypiimportalembicfromalembic.configimportConfigimportalembic.scriptimportpsutil# ==============================================================================# sanity checking...iflen(sys.argv) !=2:
raiseValueError("invoke as `python alembic_upgrade_unstamped.py {CONFIG_FILE}`")
CONFIG_file=sys.argv[1]
ifnotos.path.exists(CONFIG_file):
raiseValueError("%s is not on disk"%CONFIG_file)
CONFIG=Config(CONFIG_file)
ifnotCONFIG.get_section_option("alembic", "script_location"):
CONFIG.set_section_option("alembic", "script_location", "alembic")
sqlalchemy_url=CONFIG.get_section_option("alembic", "sqlalchemy.url")
ifnotsqlalchemy_url:
raiseValueError("no sqlalchemy.url found")
ifnotsqlalchemy_url[:11] =="sqlite:////":
raiseValueError("%s is not a compatible sqlite url"%sqlalchemy_url)
db_file=sqlalchemy_url[10:]
db_file_backup="%s-ORIGINAL"%db_file# initial backupifnotos.path.exists(db_file):
raiseValueError("DB File not found on disk:", db_file)
shutil.copy(db_file, db_file_backup)
defreset_db():
ifnotos.path.exists(db_file_backup):
raiseValueError("BACKUP does not exist; will not delete main until backed up")
os.remove(db_file)
shutil.copy(db_file_backup, db_file)
# # history prints, we don't want that# history = alembic.command.history(config=CONFIG)revisions= []
script=alembic.script.ScriptDirectory.from_config(CONFIG)
forscinscript.walk_revisions(base="base", head="heads"):
# print(sc.down_revision, sc.revision, sc.nextrev)revisions.append(sc.revision)
revisions.reverse()
PASSED: Optional[str] =Noneforrevinrevisions:
reset_db()
print("STAMPING", rev)
withpsutil.Popen(
["alembic", "-c", CONFIG_file, "stamp", rev],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
) asproc:
_data, _err=proc.communicate()
if_err:
ifb"Traceback"in_err:
print("\tERROR; Fatal")
exit(1)
print("ATTEMPT UPGRADE")
withpsutil.Popen(
["alembic", "-c", CONFIG_file, "upgrade", "head"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
) asproc:
_data, _err=proc.communicate()
if_err:
ifb"Traceback"in_err:
print("\tERROR; try next")
continuePASSED=revbreakprint("\n")
ifPASSED:
print("revision `%s` upgraded successfully"%PASSED)
else:
print("no revisions upgraded")
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Sharing this here, in case anyone needs it.
A deployment hotfix accidentally introduced Alembic onto several nodes WITHOUT correctly stamping them.
This was not detected until after several revisions had been committed to the branch. These nodes were each at varying revisions, but all thought they were at BASE. None could upgrade to HEAD, as they already had the migrations.
This script was developed to update the nodes. It does the following:
This might work with your sqlite3 installs. This could be adapted to other backends.
This assumes an upgrade from no stamp has failed; this does not detect an existing revision stamp in the database.
This uses psutil; it could be rewritten to use subprocess. I just prefer psutil.
Beta Was this translation helpful? Give feedback.
All reactions