Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions coriolis/db/sqlalchemy/alembic/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Migrations for the main database
================================

This directory contains migrations for the coriolis database. These are implemented
using `alembic`__, a lightweight database migration tool designed for usage
with `SQLAlchemy`__.

The best place to start understanding Alembic is with its own `tutorial`__. You
can also play around with the :command:`alembic` command::

$ alembic --help

.. __: https://alembic.sqlalchemy.org/en/latest/
.. __: https://www.sqlalchemy.org/
.. __: https://alembic.sqlalchemy.org/en/latest/tutorial.html

49 changes: 49 additions & 0 deletions coriolis/db/sqlalchemy/alembic/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# A generic, single database configuration.

[alembic]
# path to migration scripts
script_location = %(here)s

# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s

# default to an empty string because the migration cli will
# extract the correct value and set it programmatically before alembic is fully
# invoked.
sqlalchemy.url =
path_separator = space

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

[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

[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
80 changes: 80 additions & 0 deletions coriolis/db/sqlalchemy/alembic/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Copyright 2026 Cloudbase Solutions Srl
# All Rights Reserved.

from alembic import context
from sqlalchemy import engine_from_config
from sqlalchemy import pool

from coriolis.db.sqlalchemy import models

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

# this is the MetaData object for the various models in the database.
target_metadata = models.BASE.metadata


def run_migrations_offline():
"""Run migrations in 'offline' mode.

This configures the context with just a URL and not an Engine, though an
Engine is acceptable here as well. By skipping the Engine creation we
don't even need a DBAPI to be available.

Calls to context.execute() here emit the given string to the script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
render_as_batch=True,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)

with context.begin_transaction():
context.run_migrations()


def run_migrations_online():
"""Run migrations in 'online' mode.

In this scenario we need to create an Engine and associate a connection
with the context.
"""
connectable = config.attributes.get("connection", None)

if connectable is not None:
context.configure(
connection=connectable,
target_metadata=target_metadata,
render_as_batch=True,
)

with context.begin_transaction():
context.run_migrations()
return

# only create Engine if we don't have a Connection from the outside.
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)

with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
render_as_batch=True,
)

with context.begin_transaction():
context.run_migrations()


if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
27 changes: 27 additions & 0 deletions coriolis/db/sqlalchemy/alembic/script.py.mako
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright ${create_date.year} Cloudbase Solutions Srl
# All Rights Reserved.

"""${message}

Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""

from alembic import op
import sqlalchemy
${imports if imports else ""}

# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}


def upgrade():
${upgrades if upgrades else "pass"}


def downgrade():
${downgrades if downgrades else "pass"}
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
# Copyright 2016 Cloudbase Solutions Srl
# All Rights Reserved.

"""initial

Revision ID: 001
Revises:
Create Date: 2016-01-15 22:28:25.000000
"""

import uuid

from alembic import op
import sqlalchemy

# revision identifiers, used by Alembic.
revision = "001"
down_revision = None
branch_labels = None
depends_on = None

def upgrade(migrate_engine):
meta = sqlalchemy.MetaData()
meta.bind = migrate_engine

base_transfer_action = sqlalchemy.Table(
'base_transfer_action', meta,
def upgrade():
op.create_table(
'base_transfer_action',
sqlalchemy.Column("base_id", sqlalchemy.String(36), primary_key=True,
default=lambda: str(uuid.uuid4())),
sqlalchemy.Column('created_at', sqlalchemy.DateTime),
Expand All @@ -31,8 +42,18 @@ def upgrade(migrate_engine):
mysql_charset='utf8'
)

migration = sqlalchemy.Table(
'migration', meta,
op.create_table(
'replica',
sqlalchemy.Column("id", sqlalchemy.String(36),
sqlalchemy.ForeignKey(
'base_transfer_action.base_id'),
primary_key=True),
mysql_engine='InnoDB',
mysql_charset='utf8'
)

op.create_table(
'migration',
sqlalchemy.Column("id", sqlalchemy.String(36),
sqlalchemy.ForeignKey(
'base_transfer_action.base_id'),
Expand All @@ -44,8 +65,26 @@ def upgrade(migrate_engine):
mysql_charset='utf8'
)

task = sqlalchemy.Table(
'task', meta, sqlalchemy.Column(
op.create_table(
'tasks_execution',
sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
default=lambda: str(uuid.uuid4())),
sqlalchemy.Column('created_at', sqlalchemy.DateTime),
sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
sqlalchemy.Column('deleted', sqlalchemy.String(36)),
sqlalchemy.Column("action_id", sqlalchemy.String(36),
sqlalchemy.ForeignKey(
'base_transfer_action.base_id'),
nullable=False),
sqlalchemy.Column("status", sqlalchemy.String(100), nullable=False),
sqlalchemy.Column("number", sqlalchemy.Integer, nullable=False),
mysql_engine='InnoDB',
mysql_charset='utf8'
)

op.create_table(
'task', sqlalchemy.Column(
'id', sqlalchemy.String(36),
primary_key=True, default=lambda: str(uuid.uuid4())),
sqlalchemy.Column('created_at', sqlalchemy.DateTime),
Expand Down Expand Up @@ -76,26 +115,8 @@ def upgrade(migrate_engine):
sqlalchemy.Column("on_error", sqlalchemy.Boolean, nullable=True),
mysql_engine='InnoDB', mysql_charset='utf8')

tasks_execution = sqlalchemy.Table(
'tasks_execution', meta,
sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
default=lambda: str(uuid.uuid4())),
sqlalchemy.Column('created_at', sqlalchemy.DateTime),
sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
sqlalchemy.Column('deleted', sqlalchemy.String(36)),
sqlalchemy.Column("action_id", sqlalchemy.String(36),
sqlalchemy.ForeignKey(
'base_transfer_action.base_id'),
nullable=False),
sqlalchemy.Column("status", sqlalchemy.String(100), nullable=False),
sqlalchemy.Column("number", sqlalchemy.Integer, nullable=False),
mysql_engine='InnoDB',
mysql_charset='utf8'
)

task_progress_update = sqlalchemy.Table(
'task_progress_update', meta,
op.create_table(
'task_progress_update',
sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
default=lambda: str(uuid.uuid4())),
sqlalchemy.Column('created_at', sqlalchemy.DateTime),
Expand All @@ -112,8 +133,8 @@ def upgrade(migrate_engine):
mysql_charset='utf8'
)

task_events = sqlalchemy.Table(
'task_event', meta,
op.create_table(
'task_event',
sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
default=lambda: str(uuid.uuid4())),
sqlalchemy.Column('created_at', sqlalchemy.DateTime),
Expand All @@ -129,31 +150,8 @@ def upgrade(migrate_engine):
mysql_charset='utf8'
)

replica = sqlalchemy.Table(
'replica', meta,
sqlalchemy.Column("id", sqlalchemy.String(36),
sqlalchemy.ForeignKey(
'base_transfer_action.base_id'),
primary_key=True),
mysql_engine='InnoDB',
mysql_charset='utf8'
)

tables = (
base_transfer_action,
replica,
migration,
tasks_execution,
task,
task_progress_update,
task_events,
)

for index, table in enumerate(tables):
try:
table.create()
except Exception:
# If an error occurs, drop all tables created so far to return
# to the previously existing state.
meta.drop_all(tables=tables[:index])
raise
def downgrade():
# Downgrades were never supported by the original sqlalchemy-migrate
# migrations this revision chain was ported from.
raise NotImplementedError()
Loading
Loading