From ed872b3fe04a4ad2674d30ecb3bdc984633fdfb7 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 13 Jul 2023 12:01:26 +0100 Subject: [PATCH] db: Add initial alembic migration This was generated using the same approach first used in heat [1], but with a difference to account for the fact that, unlike heat, we have a migration added in recent times. We generate our initial schema automatically based on our models using alembic's auto-generate functionality: alembic --config masakari/db/sqlalchemy/alembic.ini \ revision -m 'Initial empty revision' alembic --config masakari/db/sqlalchemy/alembic.ini \ upgrade head alembic --config masakari/db/sqlalchemy/alembic.ini \ revision -m 'Auto-generated revision' --autogenerate The two files were then combined, formatting and imports adjusted. We then *remove* the parts of the migration related to the 'vm_moves' table and run the autogeneration step again: alembic --config masakari/db/sqlalchemy/alembic.ini \ revision -m 'Add vm moves table' --autogenerate As noted above, this is necessary since we're going to need to support alembic-based migrations for users jumping from e.g. Zed to Bobcat. Once done, the schema of these migrations and the sqlalchemy-migrate migrations are compared. This step was done by comparing the schemas of a database created by the sqlalchemy-migrate tool to the one created by alembic. First, we compared the initial alembic migration which corresponds to the state of the database after sqlalchemy-migrate migration 007: alembic --config masakari/db/sqlalchemy/alembic.ini \ upgrade 8f848eb45d03 python masakari/db/sqlalchemy/migrate_repo/manage.py version_control \ sqlite:///masakari-old.db 000 python masakari/db/sqlalchemy/migrate_repo/manage.py upgrade \ sqlite:///masakari-old.db 007 With the two databases created, we can compare them using the methodologies described in [2]. Once this is done, we do the same things for the final migration to generate its own alembic variation of the migration. alembic --config masakari/db/sqlalchemy/alembic.ini \ upgrade head python masakari/db/sqlalchemy/migrate_repo/manage.py upgrade \ sqlite:///masakari-old.db These last steps highlight some small differences between the schemas. These changes are kept to a separate change to make them more obvious. [1] https://review.opendev.org/c/openstack/heat/+/878350 [2] https://that.guru/blog/comparing-nova-db-migrations/ Change-Id: I6d0f27ba1d81e75010e8b56c70172ccf32c1abb3 Signed-off-by: Stephen Finucane --- .../8bdf5929c5a6_add_vm_moves_table.py | 58 ++++++++ .../versions/8f848eb45d03_initial_revision.py | 131 ++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 masakari/db/sqlalchemy/migrations/versions/8bdf5929c5a6_add_vm_moves_table.py create mode 100644 masakari/db/sqlalchemy/migrations/versions/8f848eb45d03_initial_revision.py diff --git a/masakari/db/sqlalchemy/migrations/versions/8bdf5929c5a6_add_vm_moves_table.py b/masakari/db/sqlalchemy/migrations/versions/8bdf5929c5a6_add_vm_moves_table.py new file mode 100644 index 00000000..1763c475 --- /dev/null +++ b/masakari/db/sqlalchemy/migrations/versions/8bdf5929c5a6_add_vm_moves_table.py @@ -0,0 +1,58 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Add vm moves table + +Revision ID: 8bdf5929c5a6 +Revises: 8f848eb45d03 +Create Date: 2023-07-13 12:13:42.240598 +""" + +from alembic import op +from oslo_db.sqlalchemy import types as oslo_db_types +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = '8bdf5929c5a6' +down_revision = '8f848eb45d03' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + 'vmoves', + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column( + 'deleted', + oslo_db_types.SoftDeleteInteger(), + nullable=True, + ), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('uuid', sa.String(length=36), nullable=False), + sa.Column('notification_uuid', sa.String(length=36), nullable=False), + sa.Column('instance_uuid', sa.String(length=36), nullable=False), + sa.Column('instance_name', sa.String(length=255), nullable=False), + sa.Column('source_host', sa.String(length=255), nullable=True), + sa.Column('dest_host', sa.String(length=255), nullable=True), + sa.Column('start_time', sa.DateTime(), nullable=True), + sa.Column('end_time', sa.DateTime(), nullable=True), + sa.Column('type', sa.String(length=36), nullable=True), + sa.Column('status', sa.String(length=255), nullable=True), + sa.Column('message', sa.Text(), nullable=True), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('uuid', name='uniq_vmove0uuid'), + ) + # ### end Alembic commands ### diff --git a/masakari/db/sqlalchemy/migrations/versions/8f848eb45d03_initial_revision.py b/masakari/db/sqlalchemy/migrations/versions/8f848eb45d03_initial_revision.py new file mode 100644 index 00000000..ae7e0c91 --- /dev/null +++ b/masakari/db/sqlalchemy/migrations/versions/8f848eb45d03_initial_revision.py @@ -0,0 +1,131 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Initial revision + +Revision ID: 8f848eb45d03 +Revises: +Create Date: 2023-07-13 12:00:07.851502 +""" + +from alembic import op +from oslo_db.sqlalchemy import types as oslo_db_types +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = '8f848eb45d03' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade() -> None: + op.create_table( + 'failover_segments', + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column( + 'deleted', + oslo_db_types.SoftDeleteInteger(), + nullable=True, + ), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('uuid', sa.String(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('service_type', sa.String(length=255), nullable=False), + sa.Column('enabled', sa.Boolean(), nullable=True), + sa.Column('description', sa.Text(), nullable=True), + sa.Column( + 'recovery_method', + sa.Enum( + 'auto', + 'reserved_host', + 'auto_priority', + 'rh_priority', + name='recovery_methods', + ), + nullable=False, + ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint( + 'name', 'deleted', name='uniq_segment0name0deleted' + ), + sa.UniqueConstraint('uuid', name='uniq_segments0uuid'), + ) + op.create_index( + 'segments_service_type_idx', + 'failover_segments', + ['service_type'], + unique=False, + ) + op.create_table( + 'notifications', + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column( + 'deleted', + oslo_db_types.SoftDeleteInteger(), + nullable=True, + ), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('notification_uuid', sa.String(length=36), nullable=False), + sa.Column('generated_time', sa.DateTime(), nullable=False), + sa.Column('type', sa.String(length=36), nullable=False), + sa.Column('payload', sa.Text(), nullable=True), + sa.Column( + 'status', + sa.Enum( + 'new', + 'running', + 'error', + 'failed', + 'ignored', + 'finished', + name='notification_status', + ), + nullable=False, + ), + sa.Column('source_host_uuid', sa.String(length=36), nullable=False), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint( + 'notification_uuid', name='uniq_notification0uuid' + ), + ) + op.create_table( + 'hosts', + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column( + 'deleted', + oslo_db_types.SoftDeleteInteger(), + nullable=True, + ), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('uuid', sa.String(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('reserved', sa.Boolean(), nullable=True), + sa.Column('type', sa.String(length=255), nullable=False), + sa.Column('control_attributes', sa.Text(), nullable=False), + sa.Column('on_maintenance', sa.Boolean(), nullable=True), + sa.Column('failover_segment_id', sa.String(length=36), nullable=False), + sa.ForeignKeyConstraint( + ['failover_segment_id'], + ['failover_segments.uuid'], + ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name', 'deleted', name='uniq_host0name0deleted'), + sa.UniqueConstraint('uuid', name='uniq_host0uuid'), + ) + op.create_index('hosts_type_idx', 'hosts', ['type'], unique=False)