diff options
author | Wojciech Dec <wdec@cisco.com> | 2016-08-16 19:27:01 +0200 |
---|---|---|
committer | Wojciech Dec <wdec@cisco.com> | 2016-08-16 19:29:27 +0200 |
commit | c3b2c2a9a22bac5cf17813c589444d3abebaa23b (patch) | |
tree | 68c2fc0cb8c32cbb8fabf69ac81e1e0ba50cff2a /networking-odl/networking_odl/db | |
parent | 3285c8e93ea59d98b392591ef6dfa5b1de3bb92d (diff) |
Adding Mitaka networking-old module with the ODL topology based port
binding resolution mechanism from https://review.openstack.org/333186
Change-Id: I10d400aac9bb639c146527f0f93e6925cb74d9de
Signed-off-by: Wojciech Dec <wdec@cisco.com>
Diffstat (limited to 'networking-odl/networking_odl/db')
15 files changed, 621 insertions, 0 deletions
diff --git a/networking-odl/networking_odl/db/__init__.py b/networking-odl/networking_odl/db/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/networking-odl/networking_odl/db/__init__.py diff --git a/networking-odl/networking_odl/db/db.py b/networking-odl/networking_odl/db/db.py new file mode 100644 index 0000000..31f4ce2 --- /dev/null +++ b/networking-odl/networking_odl/db/db.py @@ -0,0 +1,234 @@ +# Copyright (c) 2015 OpenStack Foundation +# All Rights Reserved. +# +# 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. +import datetime + +from sqlalchemy import asc +from sqlalchemy import func +from sqlalchemy import or_ + +from networking_odl.common import constants as odl_const +from networking_odl.db import models + +from neutron.db import api as db_api + +from oslo_db import api as oslo_db_api + + +def check_for_pending_or_processing_ops(session, object_uuid, operation=None): + q = session.query(models.OpendaylightJournal).filter( + or_(models.OpendaylightJournal.state == odl_const.PENDING, + models.OpendaylightJournal.state == odl_const.PROCESSING), + models.OpendaylightJournal.object_uuid == object_uuid) + if operation: + if isinstance(operation, (list, tuple)): + q = q.filter(models.OpendaylightJournal.operation.in_(operation)) + else: + q = q.filter(models.OpendaylightJournal.operation == operation) + return session.query(q.exists()).scalar() + + +def check_for_pending_delete_ops_with_parent(session, object_type, parent_id): + rows = session.query(models.OpendaylightJournal).filter( + or_(models.OpendaylightJournal.state == odl_const.PENDING, + models.OpendaylightJournal.state == odl_const.PROCESSING), + models.OpendaylightJournal.object_type == object_type, + models.OpendaylightJournal.operation == odl_const.ODL_DELETE + ).all() + + for row in rows: + if parent_id in row.data: + return True + + return False + + +def check_for_pending_or_processing_add(session, router_id, subnet_id): + rows = session.query(models.OpendaylightJournal).filter( + or_(models.OpendaylightJournal.state == odl_const.PENDING, + models.OpendaylightJournal.state == odl_const.PROCESSING), + models.OpendaylightJournal.object_type == odl_const.ODL_ROUTER_INTF, + models.OpendaylightJournal.operation == odl_const.ODL_ADD + ).all() + + for row in rows: + if router_id in row.data.values() and subnet_id in row.data.values(): + return True + + return False + + +def check_for_pending_remove_ops_with_parent(session, parent_id): + rows = session.query(models.OpendaylightJournal).filter( + or_(models.OpendaylightJournal.state == odl_const.PENDING, + models.OpendaylightJournal.state == odl_const.PROCESSING), + models.OpendaylightJournal.object_type == odl_const.ODL_ROUTER_INTF, + models.OpendaylightJournal.operation == odl_const.ODL_REMOVE + ).all() + + for row in rows: + if parent_id in row.data.values(): + return True + + return False + + +def check_for_older_ops(session, row): + q = session.query(models.OpendaylightJournal).filter( + or_(models.OpendaylightJournal.state == odl_const.PENDING, + models.OpendaylightJournal.state == odl_const.PROCESSING), + models.OpendaylightJournal.operation == row.operation, + models.OpendaylightJournal.object_uuid == row.object_uuid, + models.OpendaylightJournal.created_at < row.created_at, + models.OpendaylightJournal.id != row.id) + return session.query(q.exists()).scalar() + + +def get_all_db_rows(session): + return session.query(models.OpendaylightJournal).all() + + +def get_all_db_rows_by_state(session, state): + return session.query(models.OpendaylightJournal).filter_by( + state=state).all() + + +# Retry deadlock exception for Galera DB. +# If two (or more) different threads call this method at the same time, they +# might both succeed in changing the same row to pending, but at least one +# of them will get a deadlock from Galera and will have to retry the operation. +@db_api.retry_db_errors +def get_oldest_pending_db_row_with_lock(session): + with session.begin(): + row = session.query(models.OpendaylightJournal).filter_by( + state=odl_const.PENDING).order_by( + asc(models.OpendaylightJournal.last_retried)).with_for_update( + ).first() + if row: + update_db_row_state(session, row, odl_const.PROCESSING) + + return row + + +@oslo_db_api.wrap_db_retry(max_retries=db_api.MAX_RETRIES, + retry_on_request=True) +def update_db_row_state(session, row, state): + row.state = state + session.merge(row) + session.flush() + + +def update_pending_db_row_retry(session, row, retry_count): + if row.retry_count >= retry_count: + update_db_row_state(session, row, odl_const.FAILED) + else: + row.retry_count += 1 + update_db_row_state(session, row, odl_const.PENDING) + + +# This function is currently not used. +# Deleted resources are marked as 'deleted' in the database. +@oslo_db_api.wrap_db_retry(max_retries=db_api.MAX_RETRIES, + retry_on_request=True) +def delete_row(session, row=None, row_id=None): + if row_id: + row = session.query(models.OpendaylightJournal).filter_by( + id=row_id).one() + if row: + session.delete(row) + session.flush() + + +@oslo_db_api.wrap_db_retry(max_retries=db_api.MAX_RETRIES, + retry_on_request=True) +def create_pending_row(session, object_type, object_uuid, + operation, data): + row = models.OpendaylightJournal(object_type=object_type, + object_uuid=object_uuid, + operation=operation, data=data, + created_at=func.now(), + state=odl_const.PENDING) + session.add(row) + # Keep session flush for unit tests. NOOP for L2/L3 events since calls are + # made inside database session transaction with subtransactions=True. + session.flush() + + +@db_api.retry_db_errors +def delete_pending_rows(session, operations_to_delete): + with session.begin(): + session.query(models.OpendaylightJournal).filter( + models.OpendaylightJournal.operation.in_(operations_to_delete), + models.OpendaylightJournal.state == odl_const.PENDING).delete( + synchronize_session=False) + session.expire_all() + + +@db_api.retry_db_errors +def _update_maintenance_state(session, expected_state, state): + with session.begin(): + row = session.query(models.OpendaylightMaintenance).filter_by( + state=expected_state).with_for_update().one_or_none() + if row is None: + return False + + row.state = state + return True + + +def lock_maintenance(session): + return _update_maintenance_state(session, odl_const.PENDING, + odl_const.PROCESSING) + + +def unlock_maintenance(session): + return _update_maintenance_state(session, odl_const.PROCESSING, + odl_const.PENDING) + + +def update_maintenance_operation(session, operation=None): + """Update the current maintenance operation details. + + The function assumes the lock is held, so it mustn't be run outside of a + locked context. + """ + op_text = None + if operation: + op_text = operation.__name__ + + with session.begin(): + row = session.query(models.OpendaylightMaintenance).one_or_none() + row.processing_operation = op_text + + +def delete_rows_by_state_and_time(session, state, time_delta): + with session.begin(): + now = session.execute(func.now()).scalar() + session.query(models.OpendaylightJournal).filter( + models.OpendaylightJournal.state == state, + models.OpendaylightJournal.last_retried < now - time_delta).delete( + synchronize_session=False) + session.expire_all() + + +def reset_processing_rows(session, max_timedelta): + with session.begin(): + now = session.execute(func.now()).scalar() + max_timedelta = datetime.timedelta(seconds=max_timedelta) + rows = session.query(models.OpendaylightJournal).filter( + models.OpendaylightJournal.last_retried < now - max_timedelta, + models.OpendaylightJournal.state == odl_const.PROCESSING, + ).update({'state': odl_const.PENDING}) + + return rows diff --git a/networking-odl/networking_odl/db/migration/__init__.py b/networking-odl/networking_odl/db/migration/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/networking-odl/networking_odl/db/migration/__init__.py diff --git a/networking-odl/networking_odl/db/migration/alembic_migrations/README b/networking-odl/networking_odl/db/migration/alembic_migrations/README new file mode 100644 index 0000000..5d89e57 --- /dev/null +++ b/networking-odl/networking_odl/db/migration/alembic_migrations/README @@ -0,0 +1 @@ +This directory contains the migration scripts for the networking_odl project. diff --git a/networking-odl/networking_odl/db/migration/alembic_migrations/__init__.py b/networking-odl/networking_odl/db/migration/alembic_migrations/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/networking-odl/networking_odl/db/migration/alembic_migrations/__init__.py diff --git a/networking-odl/networking_odl/db/migration/alembic_migrations/env.py b/networking-odl/networking_odl/db/migration/alembic_migrations/env.py new file mode 100644 index 0000000..9405ae0 --- /dev/null +++ b/networking-odl/networking_odl/db/migration/alembic_migrations/env.py @@ -0,0 +1,99 @@ +# Copyright 2015 OpenStack Foundation +# +# 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. +# + +from logging import config as logging_config + +from alembic import context +from oslo_config import cfg +from oslo_db.sqlalchemy import session +import sqlalchemy as sa +from sqlalchemy import event + +from neutron.db.migration.alembic_migrations import external +from neutron.db.migration.models import head # noqa +from neutron.db import model_base + +MYSQL_ENGINE = None +ODL_VERSION_TABLE = 'odl_alembic_version' +config = context.config +neutron_config = config.neutron_config +logging_config.fileConfig(config.config_file_name) +target_metadata = model_base.BASEV2.metadata + + +def set_mysql_engine(): + try: + mysql_engine = neutron_config.command.mysql_engine + except cfg.NoSuchOptError: + mysql_engine = None + + global MYSQL_ENGINE + MYSQL_ENGINE = (mysql_engine or + model_base.BASEV2.__table_args__['mysql_engine']) + + +def include_object(object, name, type_, reflected, compare_to): + if type_ == 'table' and name in external.TABLES: + return False + else: + return True + + +def run_migrations_offline(): + set_mysql_engine() + + kwargs = dict() + if neutron_config.database.connection: + kwargs['url'] = neutron_config.database.connection + else: + kwargs['dialect_name'] = neutron_config.database.engine + kwargs['include_object'] = include_object + kwargs['version_table'] = ODL_VERSION_TABLE + context.configure(**kwargs) + + with context.begin_transaction(): + context.run_migrations() + + +@event.listens_for(sa.Table, 'after_parent_attach') +def set_storage_engine(target, parent): + if MYSQL_ENGINE: + target.kwargs['mysql_engine'] = MYSQL_ENGINE + + +def run_migrations_online(): + set_mysql_engine() + engine = session.create_engine(neutron_config.database.connection) + + connection = engine.connect() + context.configure( + connection=connection, + target_metadata=target_metadata, + include_object=include_object, + version_table=ODL_VERSION_TABLE + ) + + try: + with context.begin_transaction(): + context.run_migrations() + finally: + connection.close() + engine.dispose() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/networking-odl/networking_odl/db/migration/alembic_migrations/script.py.mako b/networking-odl/networking_odl/db/migration/alembic_migrations/script.py.mako new file mode 100644 index 0000000..9e0b2ce --- /dev/null +++ b/networking-odl/networking_odl/db/migration/alembic_migrations/script.py.mako @@ -0,0 +1,36 @@ +# Copyright ${create_date.year} <PUT YOUR NAME/COMPANY HERE> +# +# 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. +# + +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision} +Create Date: ${create_date} + +""" + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +% if branch_labels: +branch_labels = ${repr(branch_labels)} +%endif + +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +def upgrade(): + ${upgrades if upgrades else "pass"} diff --git a/networking-odl/networking_odl/db/migration/alembic_migrations/versions/CONTRACT_HEAD b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/CONTRACT_HEAD new file mode 100644 index 0000000..b7dbc31 --- /dev/null +++ b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/CONTRACT_HEAD @@ -0,0 +1 @@ +383acb0d38a0 diff --git a/networking-odl/networking_odl/db/migration/alembic_migrations/versions/EXPAND_HEAD b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/EXPAND_HEAD new file mode 100644 index 0000000..34912ba --- /dev/null +++ b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/EXPAND_HEAD @@ -0,0 +1 @@ +703dbf02afde diff --git a/networking-odl/networking_odl/db/migration/alembic_migrations/versions/b89a299e19f9_initial_branchpoint.py b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/b89a299e19f9_initial_branchpoint.py new file mode 100644 index 0000000..d80815d --- /dev/null +++ b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/b89a299e19f9_initial_branchpoint.py @@ -0,0 +1,28 @@ +# 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 odl db, branchpoint + +Revision ID: b89a299e19f9 +Revises: None +Create Date: 2015-09-03 22:22:22.222222 + +""" + +# revision identifiers, used by Alembic. +revision = 'b89a299e19f9' +down_revision = None + + +def upgrade(): + pass diff --git a/networking-odl/networking_odl/db/migration/alembic_migrations/versions/mitaka/contract/383acb0d38a0_initial_contract.py b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/mitaka/contract/383acb0d38a0_initial_contract.py new file mode 100644 index 0000000..43959c0 --- /dev/null +++ b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/mitaka/contract/383acb0d38a0_initial_contract.py @@ -0,0 +1,36 @@ +# 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. +# + +"""Start of odl contract branch + +Revision ID: 383acb0d38a0 +Revises: b89a299e19f9 +Create Date: 2015-09-03 22:27:49.306394 + +""" + +from neutron.db import migration +from neutron.db.migration import cli + + +# revision identifiers, used by Alembic. +revision = '383acb0d38a0' +down_revision = 'b89a299e19f9' +branch_labels = (cli.CONTRACT_BRANCH,) + +# milestone identifier, used by neutron-db-manage +neutron_milestone = [migration.MITAKA] + + +def upgrade(): + pass diff --git a/networking-odl/networking_odl/db/migration/alembic_migrations/versions/mitaka/expand/247501328046_initial_expand.py b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/mitaka/expand/247501328046_initial_expand.py new file mode 100644 index 0000000..71d24b3 --- /dev/null +++ b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/mitaka/expand/247501328046_initial_expand.py @@ -0,0 +1,32 @@ +# 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. +# + +"""Start of odl expand branch + +Revision ID: 247501328046 +Revises: b89a299e19f9 +Create Date: 2015-09-03 22:27:49.292238 + +""" + +from neutron.db.migration import cli + + +# revision identifiers, used by Alembic. +revision = '247501328046' +down_revision = 'b89a299e19f9' +branch_labels = (cli.EXPAND_BRANCH,) + + +def upgrade(): + pass diff --git a/networking-odl/networking_odl/db/migration/alembic_migrations/versions/mitaka/expand/37e242787ae5_opendaylight_neutron_mechanism_driver_.py b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/mitaka/expand/37e242787ae5_opendaylight_neutron_mechanism_driver_.py new file mode 100644 index 0000000..71d8273 --- /dev/null +++ b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/mitaka/expand/37e242787ae5_opendaylight_neutron_mechanism_driver_.py @@ -0,0 +1,54 @@ +# Copyright (c) 2015 OpenStack Foundation +# +# 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. +# + +"""Opendaylight Neutron mechanism driver refactor + +Revision ID: 37e242787ae5 +Revises: 247501328046 +Create Date: 2015-10-30 22:09:27.221767 + +""" +from neutron.db import migration + + +# revision identifiers, used by Alembic. +revision = '37e242787ae5' +down_revision = '247501328046' + +# milestone identifier, used by neutron-db-manage +neutron_milestone = [migration.MITAKA] + + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.create_table( + 'opendaylightjournal', + sa.Column('id', sa.String(36), primary_key=True), + sa.Column('object_type', sa.String(36), nullable=False), + sa.Column('object_uuid', sa.String(36), nullable=False), + sa.Column('operation', sa.String(36), nullable=False), + sa.Column('data', sa.PickleType, nullable=True), + sa.Column('state', + sa.Enum('pending', 'processing', 'failed', 'completed', + name='state'), + nullable=False, default='pending'), + sa.Column('retry_count', sa.Integer, default=0), + sa.Column('created_at', sa.DateTime, default=sa.func.now()), + sa.Column('last_retried', sa.TIMESTAMP, server_default=sa.func.now(), + onupdate=sa.func.now()) + ) diff --git a/networking-odl/networking_odl/db/migration/alembic_migrations/versions/newton/expand/703dbf02afde_add_journal_maintenance_table.py b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/newton/expand/703dbf02afde_add_journal_maintenance_table.py new file mode 100644 index 0000000..bbe0c46 --- /dev/null +++ b/networking-odl/networking_odl/db/migration/alembic_migrations/versions/newton/expand/703dbf02afde_add_journal_maintenance_table.py @@ -0,0 +1,52 @@ +# Copyright 2016 Red Hat Inc. +# +# 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 journal maintenance table + +Revision ID: 703dbf02afde +Revises: 37e242787ae5 +Create Date: 2016-04-12 10:49:31.802663 + +""" + +# revision identifiers, used by Alembic. +revision = '703dbf02afde' +down_revision = '37e242787ae5' + +from alembic import op +from oslo_utils import uuidutils +import sqlalchemy as sa + +from networking_odl.common import constants as odl_const + + +def upgrade(): + maint_table = op.create_table( + 'opendaylight_maintenance', + sa.Column('id', sa.String(36), primary_key=True), + sa.Column('state', sa.Enum(odl_const.PENDING, odl_const.PROCESSING, + name='state'), + nullable=False), + sa.Column('processing_operation', sa.String(70)), + sa.Column('lock_updated', sa.TIMESTAMP, nullable=False, + server_default=sa.func.now(), + onupdate=sa.func.now()) + ) + + # Insert the only row here that is used to synchronize the lock between + # different Neutron processes. + op.bulk_insert(maint_table, + [{'id': uuidutils.generate_uuid(), + 'state': odl_const.PENDING}]) diff --git a/networking-odl/networking_odl/db/models.py b/networking-odl/networking_odl/db/models.py new file mode 100644 index 0000000..0416ed1 --- /dev/null +++ b/networking-odl/networking_odl/db/models.py @@ -0,0 +1,47 @@ +# Copyright (c) 2015 OpenStack Foundation +# All Rights Reserved. +# +# 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. + +import sqlalchemy as sa + +from networking_odl.common import constants as odl_const +from neutron.db import model_base +from neutron.db.models_v2 import HasId + + +class OpendaylightJournal(model_base.BASEV2, HasId): + __tablename__ = 'opendaylightjournal' + + object_type = sa.Column(sa.String(36), nullable=False) + object_uuid = sa.Column(sa.String(36), nullable=False) + operation = sa.Column(sa.String(36), nullable=False) + data = sa.Column(sa.PickleType, nullable=True) + state = sa.Column(sa.Enum(odl_const.PENDING, odl_const.FAILED, + odl_const.PROCESSING, odl_const.COMPLETED), + nullable=False, default=odl_const.PENDING) + retry_count = sa.Column(sa.Integer, default=0) + created_at = sa.Column(sa.DateTime, server_default=sa.func.now()) + last_retried = sa.Column(sa.TIMESTAMP, server_default=sa.func.now(), + onupdate=sa.func.now()) + + +class OpendaylightMaintenance(model_base.BASEV2, HasId): + __tablename__ = 'opendaylight_maintenance' + + state = sa.Column(sa.Enum(odl_const.PENDING, odl_const.PROCESSING), + nullable=False) + processing_operation = sa.Column(sa.String(70)) + lock_updated = sa.Column(sa.TIMESTAMP, nullable=False, + server_default=sa.func.now(), + onupdate=sa.func.now()) |