Skip to content

Commit

Permalink
Integrate alembic check into basic server tests
Browse files Browse the repository at this point in the history
Starting with Alembic v1.9.0 the command, `alembic check` is available
which will succeed if no migrations are required, and fail if it detects
that a migration is necessary.

We also remove the unused `alembic/alembic.ini`, drop the need for a
separate `tox` environment, remove the need for a `pbench-server.cfg`
file entirely by reverting to the original env.py as generated by
`alembic init alembic`.

We also collapse the existing migrations to one since we just need one
to move from an empty database to our current schema.
  • Loading branch information
portante committed Jan 17, 2023
1 parent 5e50996 commit 32930cd
Show file tree
Hide file tree
Showing 10 changed files with 64 additions and 282 deletions.
5 changes: 5 additions & 0 deletions exec-tests
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ if [[ "${major}" == "all" || "${major}" == "server" ]]; then
${_ECHO} verify_make_source_tree server || rc=1
fi

# Verify no database migrations would be generated.
if [[ "${subtst:-alembic}" == "alembic" && ${rc} -eq 0 ]]; then
(cd lib/pbench/server/database && ${ECHO} alembic check) || rc=1
fi

# Run the server functional tests
if [[ "${subtst}" == "functional" && ${rc} -eq 0 ]]; then
server_arg=${1}
Expand Down
35 changes: 25 additions & 10 deletions lib/pbench/server/database/alembic.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ script_location = alembic
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s

# timezone to use when rendering the date
# within the migration file as well as the filename.
# sys.path path, will be prepended to sys.path if present.
# defaults to the current working directory.
prepend_sys_path = .

# timezone to use when rendering the date within the migration file
# as well as the filename.
# If specified, requires the python-dateutil library that can be
# installed by adding `alembic[tz]` to the pip requirements
# string value is passed to dateutil.tz.gettz()
# leave blank for localtime
# timezone =
Expand All @@ -26,10 +32,19 @@ script_location = alembic
# versions/ directory
# sourceless = false

# version location specification; this defaults
# version location specification; This defaults
# to alembic/versions. When using multiple version
# directories, initial revisions must be specified with --version-path
# version_locations = %(here)s/bar %(here)s/bat alembic/versions
# directories, initial revisions must be specified with --version-path.
# The path separator used here should be the separator specified by "version_path_separator"
# version_locations = %(here)s/bar:%(here)s/bat:alembic/versions

# version path separator; As mentioned above, this is the character used to split
# version_locations. Valid values are:
#
# version_path_separator = :
# version_path_separator = ;
# version_path_separator = space
version_path_separator = os # default: use os.pathsep

# the output encoding used when revision files
# are written from script.py.mako
Expand All @@ -44,17 +59,17 @@ sqlalchemy.url = postgresql://pbench:pbench@localhost:5432/pbench
# detail and examples

# format using "black" - use the console_scripts runner, against the "black" entrypoint
# hooks=black
# black.type=console_scripts
# black.entrypoint=black
# black.options=-l 79
# hooks = black
# black.type = console_scripts
# black.entrypoint = black
# black.options = -l 79 REVISION_SCRIPT_FILENAME

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

[handlers]
keys = console, fileHandler
keys = console

[formatters]
keys = generic
Expand Down
13 changes: 0 additions & 13 deletions lib/pbench/server/database/alembic.run

This file was deleted.

89 changes: 0 additions & 89 deletions lib/pbench/server/database/alembic/alembic.ini

This file was deleted.

76 changes: 22 additions & 54 deletions lib/pbench/server/database/alembic/env.py
Original file line number Diff line number Diff line change
@@ -1,62 +1,28 @@
"""Alembic Migration Driver
This file was auto generated by `alembic init alembic` but was manually altered
to suit the needs of the Pbench server. Re-running `alembic init alembic` will
overwrite these changes!
This Python script runs whenever the alembic migration tool is invoked in
/opt/pbench-server/lib/server/database; it contains instructions to configure
and generate a SQLAlchemy engine, procure a connection from that engine along
with a transaction, and then invoke the migration engine, using the connection
as a source of database connectivity.
This requires access to Pbench library modules and the Pbench server config file
and thus must be run with
export PYTHONPATH=/opt/pbench-server/lib:${PYTHONPATH}
export _PBENCH_SERVER_CONFIG=/opt/pbench-server/lib/config/pbench-server.cfg
Examples:
alembic upgrade head # upgrade database to the latest
alembic downgrade base # downgrade to the original tracked state
"""
import logging
import sys
from logging.config import fileConfig

from alembic import context
from sqlalchemy import create_engine
from sqlalchemy import engine_from_config, pool

from pbench.server.api import get_server_config
from pbench.server.database.database import Database

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

# Add syslog handler to send logs to journald
log = logging.getLogger("alembic")
handler = logging.handlers.SysLogHandler("/dev/log")
log.addHandler(handler)

# add your model's MetaData object here for 'autogenerate' support:
# Interpret the config file for Python logging and setup the loggers.
fileConfig(config.config_file_name)

# Add your model's MetaData object here for 'autogenerate' support:
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = Database.Base.metadata

# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.

try:
server_config = get_server_config()
url = Database.get_engine_uri(server_config)
except Exception as e:
print(e)
sys.exit(1)
# Other values from the config, defined by the needs of env.py, can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.


def run_migrations_offline(url: str):
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL and not an Engine, though an
Expand All @@ -65,6 +31,7 @@ def run_migrations_offline(url: str):
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,
Expand All @@ -76,14 +43,17 @@ def run_migrations_offline(url: str):
context.run_migrations()


def run_migrations_online(url: str):
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 = create_engine(url)
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)
Expand All @@ -93,8 +63,6 @@ def run_migrations_online(url: str):


if context.is_offline_mode():
print("running migration offline")
run_migrations_offline(url)
run_migrations_offline()
else:
print("running migration online")
run_migrations_online(url)
run_migrations_online()

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
"""Initial tables
"""Initial database schema
Revision ID: 274bab07e3f8
Revises: 62eddcec4817
Create Date: 2023-01-16 05:54:33.496244
Revision ID: fa12f45a2a5a
Revises:
Create Date: 2023-01-16 18:33:29.144835
Since we are adding Alembic migrations after we have already been using our
database in various contexts, this "Initial tables" migration describes how to
bring an empty database up to the state of the database as of commit 6a764f154.
That commit was the latest working version of the Pbench Server deployed in Red
Hat's staging environment.
database in various contexts, this "Initial database schema" migration describes
how to bring an empty database up to the state of the database as of commit
6a764f154. That commit was the latest working version of the Pbench Server
deployed in Red Hat's staging environment.
"""
from alembic import op
import sqlalchemy as sa

from pbench.server.database.models import TZDateTime

# revision identifiers, used by Alembic.
revision = "274bab07e3f8"
down_revision = "62eddcec4817"
revision = "fa12f45a2a5a"
down_revision = None
branch_labels = None
depends_on = None

Expand Down Expand Up @@ -60,7 +60,7 @@ def upgrade():
op.create_table(
"datasets",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("name", sa.String(length=255), nullable=False),
sa.Column("name", sa.String(length=1024), nullable=False),
sa.Column("owner_id", sa.String(length=255), nullable=False),
sa.Column("access", sa.String(length=255), nullable=False),
sa.Column("resource_id", sa.String(length=255), nullable=False),
Expand Down
Loading

0 comments on commit 32930cd

Please sign in to comment.