diff --git a/devstack/lib/watcher b/devstack/lib/watcher index 80723cc58..aad396033 100644 --- a/devstack/lib/watcher +++ b/devstack/lib/watcher @@ -188,7 +188,7 @@ function init_watcher { recreate_database watcher # Create watcher schema - $WATCHER_BIN_DIR/watcher-db-manage --config-file $WATCHER_CONF create_schema + $WATCHER_BIN_DIR/watcher-db-manage --config-file $WATCHER_CONF upgrade head fi create_watcher_cache_dir } diff --git a/watcher/cmd/dbmanage.py b/watcher/cmd/dbmanage.py index 35378aae7..45e36adba 100644 --- a/watcher/cmd/dbmanage.py +++ b/watcher/cmd/dbmanage.py @@ -71,7 +71,7 @@ def add_command_parsers(subparsers): "Optionally, use --revision to specify an alembic revision " "string to upgrade to.") parser.set_defaults(func=DBCommand.upgrade) - parser.add_argument('--revision', nargs='?') + parser.add_argument('revision', nargs='?') parser = subparsers.add_parser( 'downgrade', @@ -79,10 +79,10 @@ def add_command_parsers(subparsers): "While optional, one should generally use --revision to " "specify the alembic revision string to downgrade to.") parser.set_defaults(func=DBCommand.downgrade) - parser.add_argument('--revision', nargs='?') + parser.add_argument('revision', nargs='?') parser = subparsers.add_parser('stamp') - parser.add_argument('--revision', nargs='?') + parser.add_argument('revision', nargs='?') parser.set_defaults(func=DBCommand.stamp) parser = subparsers.add_parser( diff --git a/watcher/db/sqlalchemy/alembic/README b/watcher/db/sqlalchemy/alembic/README deleted file mode 100644 index 468afdbc0..000000000 --- a/watcher/db/sqlalchemy/alembic/README +++ /dev/null @@ -1,15 +0,0 @@ -Please see https://alembic.readthedocs.org/en/latest/index.html for general documentation - -To create alembic migrations use: -$ watcher-db-manage revision --message "description of revision" --autogenerate - -Stamp db with most recent migration version, without actually running migrations -$ watcher-db-manage stamp head - -Upgrade can be performed by: -$ watcher-db-manage upgrade -$ watcher-db-manage upgrade head - -Downgrading db: -$ watcher-db-manage downgrade -$ watcher-db-manage downgrade base diff --git a/watcher/db/sqlalchemy/alembic/README.rst b/watcher/db/sqlalchemy/alembic/README.rst new file mode 100644 index 000000000..b70a6d255 --- /dev/null +++ b/watcher/db/sqlalchemy/alembic/README.rst @@ -0,0 +1,62 @@ +The migrations in the alembic/versions contain the changes needed to migrate +from older Watcher releases to newer versions. A migration occurs by executing +a script that details the changes needed to upgrade/downgrade the database. The +migration scripts are ordered so that multiple scripts can run sequentially to +update the database. The scripts are executed by Watcher's migration wrapper +which uses the Alembic library to manage the migration. Watcher supports +migration from Ocata or later. + + +If you are a deployer or developer and want to migrate from Ocata to later +release you must first add version tracking to the database:: + + $ watcher-db-manage --config-file /path/to/watcher.conf stamp ocata + + +You can upgrade to the latest database version via:: + + $ watcher-db-manage --config-file /path/to/watcher.conf upgrade head + + +To check the current database version:: + + $ watcher-db-manage --config-file /path/to/watcher.conf current + + +To create a script to run the migration offline:: + + $ watcher-db-manage --config-file /path/to/watcher.conf upgrade head --sql + + +To run the offline migration between specific migration versions:: + + $ watcher-db-manage --config-file /path/to/watcher.conf upgrade \ + : --sql + + +Upgrade the database incrementally:: + + $ watcher-db-manage --config-file /path/to/watcher.conf upgrade --delta \ + <# of revs> + + +Downgrade the database by a certain number of revisions:: + + $ watcher-db-manage --config-file /path/to/watcher.conf downgrade --delta \ + <# of revs> + + +Create new revision:: + + $ watcher-db-manage --config-file /path/to/watcher.conf revision \ + -m "description of revision" --autogenerate + + +Create a blank file:: + + $ watcher-db-manage --config-file /path/to/watcher.conf revision \ + -m "description of revision" + +Please see https://alembic.readthedocs.org/en/latest/index.html for general +documentation + diff --git a/watcher/db/sqlalchemy/alembic/versions/001_ocata.py b/watcher/db/sqlalchemy/alembic/versions/001_ocata.py new file mode 100644 index 000000000..22d722011 --- /dev/null +++ b/watcher/db/sqlalchemy/alembic/versions/001_ocata.py @@ -0,0 +1,203 @@ +"""ocata release + +Revision ID: 9894235b4278 +Revises: None +Create Date: 2017-02-01 09:40:05.065981 + +""" +from alembic import op +import oslo_db +import sqlalchemy as sa +from watcher.db.sqlalchemy import models + + +# revision identifiers, used by Alembic. +revision = '001' +down_revision = None + + +def upgrade(): + op.create_table( + 'goals', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(), + nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', sa.String(length=36), nullable=True), + sa.Column('name', sa.String(length=63), nullable=False), + sa.Column('display_name', sa.String(length=63), nullable=False), + sa.Column('efficacy_specification', models.JSONEncodedList(), + nullable=False), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name', 'deleted', name='uniq_goals0name'), + sa.UniqueConstraint('uuid', name='uniq_goals0uuid') + ) + + op.create_table( + 'scoring_engines', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(), + nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', sa.String(length=36), nullable=False), + sa.Column('name', sa.String(length=63), nullable=False), + sa.Column('description', sa.String(length=255), nullable=True), + sa.Column('metainfo', sa.Text(), nullable=True), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name', 'deleted', + name='uniq_scoring_engines0name'), + sa.UniqueConstraint('uuid', name='uniq_scoring_engines0uuid') + ) + + op.create_table( + 'services', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(), + nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('host', sa.String(length=255), nullable=False), + sa.Column('last_seen_up', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('host', 'name', 'deleted', + name='uniq_services0host0name0deleted') + ) + + op.create_table( + 'strategies', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(), + nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', sa.String(length=36), nullable=True), + sa.Column('name', sa.String(length=63), nullable=False), + sa.Column('display_name', sa.String(length=63), nullable=False), + sa.Column('goal_id', sa.Integer(), nullable=False), + sa.Column('parameters_spec', models.JSONEncodedDict(), + nullable=True), + sa.ForeignKeyConstraint(['goal_id'], ['goals.id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name', 'deleted', name='uniq_strategies0name'), + sa.UniqueConstraint('uuid', name='uniq_strategies0uuid') + ) + + op.create_table( + 'audit_templates', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(), + nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', sa.String(length=36), nullable=True), + sa.Column('name', sa.String(length=63), nullable=True), + sa.Column('description', sa.String(length=255), nullable=True), + sa.Column('goal_id', sa.Integer(), nullable=False), + sa.Column('strategy_id', sa.Integer(), nullable=True), + sa.Column('scope', models.JSONEncodedList(), + nullable=True), + sa.ForeignKeyConstraint(['goal_id'], ['goals.id'], ), + sa.ForeignKeyConstraint(['strategy_id'], ['strategies.id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name', 'deleted', + name='uniq_audit_templates0name'), + sa.UniqueConstraint('uuid', name='uniq_audit_templates0uuid') + ) + op.create_table( + 'audits', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(), + nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', sa.String(length=36), nullable=True), + sa.Column('audit_type', sa.String(length=20), nullable=True), + sa.Column('state', sa.String(length=20), nullable=True), + sa.Column('parameters', models.JSONEncodedDict(), nullable=True), + sa.Column('interval', sa.Integer(), nullable=True), + sa.Column('goal_id', sa.Integer(), nullable=False), + sa.Column('strategy_id', sa.Integer(), nullable=True), + sa.Column('scope', models.JSONEncodedList(), nullable=True), + sa.Column('auto_trigger', sa.Boolean(), nullable=False), + sa.ForeignKeyConstraint(['goal_id'], ['goals.id'], ), + sa.ForeignKeyConstraint(['strategy_id'], ['strategies.id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('uuid', name='uniq_audits0uuid') + ) + op.create_table( + 'action_plans', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(), + nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', sa.String(length=36), nullable=True), + sa.Column('audit_id', sa.Integer(), nullable=False), + sa.Column('strategy_id', sa.Integer(), nullable=False), + sa.Column('state', sa.String(length=20), nullable=True), + sa.Column('global_efficacy', models.JSONEncodedDict(), nullable=True), + sa.ForeignKeyConstraint(['audit_id'], ['audits.id'], ), + sa.ForeignKeyConstraint(['strategy_id'], ['strategies.id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('uuid', name='uniq_action_plans0uuid') + ) + + op.create_table( + 'actions', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(), + nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', sa.String(length=36), nullable=False), + sa.Column('action_plan_id', sa.Integer(), nullable=False), + sa.Column('action_type', sa.String(length=255), nullable=False), + sa.Column('input_parameters', models.JSONEncodedDict(), nullable=True), + sa.Column('state', sa.String(length=20), nullable=True), + sa.Column('parents', models.JSONEncodedList(), nullable=True), + sa.ForeignKeyConstraint(['action_plan_id'], ['action_plans.id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('uuid', name='uniq_actions0uuid') + ) + + op.create_table( + 'efficacy_indicators', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(), + nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', sa.String(length=36), nullable=True), + sa.Column('name', sa.String(length=63), nullable=True), + sa.Column('description', sa.String(length=255), nullable=True), + sa.Column('unit', sa.String(length=63), nullable=True), + sa.Column('value', sa.Numeric(), nullable=True), + sa.Column('action_plan_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['action_plan_id'], ['action_plans.id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('uuid', name='uniq_efficacy_indicators0uuid') + ) + + +def downgrade(): + op.drop_table('efficacy_indicators') + op.drop_table('actions') + op.drop_table('action_plans') + op.drop_table('audits') + op.drop_table('audit_templates') + op.drop_table('strategies') + op.drop_table('services') + op.drop_table('scoring_engines') + op.drop_table('goals') diff --git a/watcher/db/sqlalchemy/alembic/versions/__init__.py b/watcher/db/sqlalchemy/alembic/versions/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/watcher/db/sqlalchemy/migration.py b/watcher/db/sqlalchemy/migration.py index 6d34341b4..b342945fe 100644 --- a/watcher/db/sqlalchemy/migration.py +++ b/watcher/db/sqlalchemy/migration.py @@ -54,7 +54,7 @@ def upgrade(revision, config=None): revision = revision or 'head' config = config or _alembic_config() - alembic.command.upgrade(config, revision or 'head') + alembic.command.upgrade(config, revision) def create_schema(config=None, engine=None):