aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/common/sql
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/common/sql')
-rw-r--r--keystone-moon/keystone/common/sql/core.py110
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/README2
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/__init__.py17
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/045_placeholder.py21
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/046_placeholder.py21
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/047_placeholder.py21
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/049_placeholder.py21
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/050_fk_consistent_indexes.py43
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/051_add_id_mapping.py41
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/052_add_auth_url_to_region.py27
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/053_endpoint_to_region_association.py90
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/054_add_actor_id_index.py27
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/055_add_indexes_to_token_table.py25
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/060_placeholder.py18
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/061_add_parent_project.py41
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/062_drop_assignment_role_fk.py35
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/063_drop_region_auth_url.py24
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/064_drop_user_and_group_fk.py39
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/065_add_domain_config.py46
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/066_fixup_service_name_value.py40
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/067_drop_redundant_mysql_index.py25
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/067_kilo.py (renamed from keystone-moon/keystone/common/sql/migrate_repo/versions/044_icehouse.py)100
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/073_insert_assignment_inherited_pk.py3
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/076_placeholder.py (renamed from keystone-moon/keystone/common/sql/migrate_repo/versions/056_placeholder.py)4
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/077_placeholder.py (renamed from keystone-moon/keystone/common/sql/migrate_repo/versions/057_placeholder.py)4
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/078_placeholder.py (renamed from keystone-moon/keystone/common/sql/migrate_repo/versions/058_placeholder.py)4
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/079_placeholder.py (renamed from keystone-moon/keystone/common/sql/migrate_repo/versions/059_placeholder.py)4
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/080_placeholder.py18
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/081_add_endpoint_policy_table.py54
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/082_add_federation_tables.py97
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/083_add_oauth1_tables.py75
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/084_add_revoke_tables.py55
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/085_add_endpoint_filtering_table.py70
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/086_add_duplicate_constraint_trusts.py (renamed from keystone-moon/keystone/common/sql/migrate_repo/versions/048_placeholder.py)17
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/087_implied_roles.py43
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/088_domain_specific_roles.py60
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/089_add_root_of_all_domains.py76
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/090_add_local_user_and_password_tables.py42
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/091_migrate_data_to_local_user_and_password_tables.py66
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/092_make_implied_roles_fks_cascaded.py46
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/093_migrate_domains_to_projects.py125
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/094_add_federated_user_table.py43
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/095_add_integer_pkey_to_revocation_event_table.py62
-rw-r--r--keystone-moon/keystone/common/sql/migrate_repo/versions/096_drop_role_name_constraint.py50
-rw-r--r--keystone-moon/keystone/common/sql/migration_helpers.py129
45 files changed, 1185 insertions, 796 deletions
diff --git a/keystone-moon/keystone/common/sql/core.py b/keystone-moon/keystone/common/sql/core.py
index ebd61bb7..cb026356 100644
--- a/keystone-moon/keystone/common/sql/core.py
+++ b/keystone-moon/keystone/common/sql/core.py
@@ -18,14 +18,13 @@ Before using this module, call initialize(). This has to be done before
CONF() because it sets up configuration options.
"""
-import contextlib
import functools
from oslo_config import cfg
from oslo_db import exception as db_exception
from oslo_db import options as db_options
+from oslo_db.sqlalchemy import enginefacade
from oslo_db.sqlalchemy import models
-from oslo_db.sqlalchemy import session as db_session
from oslo_log import log
from oslo_serialization import jsonutils
import six
@@ -34,6 +33,7 @@ from sqlalchemy.ext import declarative
from sqlalchemy.orm.attributes import flag_modified, InstrumentedAttribute
from sqlalchemy import types as sql_types
+from keystone.common import driver_hints
from keystone.common import utils
from keystone import exception
from keystone.i18n import _
@@ -68,7 +68,6 @@ flag_modified = flag_modified
def initialize():
"""Initialize the module."""
-
db_options.set_defaults(
CONF,
connection="sqlite:///keystone.db")
@@ -166,77 +165,47 @@ class ModelDictMixin(object):
return {name: getattr(self, name) for name in names}
-_engine_facade = None
+_main_context_manager = None
-def _get_engine_facade():
- global _engine_facade
+def _get_main_context_manager():
+ global _main_context_manager
- if not _engine_facade:
- _engine_facade = db_session.EngineFacade.from_config(CONF)
+ if not _main_context_manager:
+ _main_context_manager = enginefacade.transaction_context()
- return _engine_facade
+ return _main_context_manager
def cleanup():
- global _engine_facade
+ global _main_context_manager
- _engine_facade = None
+ _main_context_manager = None
-def get_engine():
- return _get_engine_facade().get_engine()
+_CONTEXT = None
-def get_session(expire_on_commit=False):
- return _get_engine_facade().get_session(expire_on_commit=expire_on_commit)
+def _get_context():
+ global _CONTEXT
+ if _CONTEXT is None:
+ # NOTE(dims): Delay the `threading.local` import to allow for
+ # eventlet/gevent monkeypatching to happen
+ import threading
+ _CONTEXT = threading.local()
+ return _CONTEXT
-@contextlib.contextmanager
-def transaction(expire_on_commit=False):
- """Return a SQLAlchemy session in a scoped transaction."""
- session = get_session(expire_on_commit=expire_on_commit)
- with session.begin():
- yield session
+def session_for_read():
+ return _get_main_context_manager().reader.using(_get_context())
-def truncated(f):
- """Ensure list truncation is detected in Driver list entity methods.
+def session_for_write():
+ return _get_main_context_manager().writer.using(_get_context())
- This is designed to wrap and sql Driver list_{entity} methods in order to
- calculate if the resultant list has been truncated. Provided a limit dict
- is found in the hints list, we increment the limit by one so as to ask the
- wrapped function for one more entity than the limit, and then once the list
- has been generated, we check to see if the original limit has been
- exceeded, in which case we truncate back to that limit and set the
- 'truncated' boolean to 'true' in the hints limit dict.
- """
- @functools.wraps(f)
- def wrapper(self, hints, *args, **kwargs):
- if not hasattr(hints, 'limit'):
- raise exception.UnexpectedError(
- _('Cannot truncate a driver call without hints list as '
- 'first parameter after self '))
-
- if hints.limit is None:
- return f(self, hints, *args, **kwargs)
-
- # A limit is set, so ask for one more entry than we need
- list_limit = hints.limit['limit']
- hints.set_limit(list_limit + 1)
- ref_list = f(self, hints, *args, **kwargs)
-
- # If we got more than the original limit then trim back the list and
- # mark it truncated. In both cases, make sure we set the limit back
- # to its original value.
- if len(ref_list) > list_limit:
- hints.set_limit(list_limit, truncated=True)
- return ref_list[:list_limit]
- else:
- hints.set_limit(list_limit)
- return ref_list
- return wrapper
+def truncated(f):
+ return driver_hints.truncated(f)
class _WontMatch(Exception):
@@ -325,42 +294,41 @@ def _filter(model, query, hints):
satisfied_filters.append(filter_)
return query.filter(query_term)
- def exact_filter(model, filter_, cumulative_filter_dict):
+ def exact_filter(model, query, filter_, satisfied_filters):
"""Applies an exact filter to a query.
:param model: the table model in question
+ :param query: query to apply filters to
:param dict filter_: describes this filter
- :param dict cumulative_filter_dict: describes the set of exact filters
- built up so far
-
+ :param list satisfied_filters: filter_ will be added if it is
+ satisfied.
+ :returns query: query updated to add any exact filters we could
+ satisfy
"""
key = filter_['name']
col = getattr(model, key)
if isinstance(col.property.columns[0].type, sql.types.Boolean):
- cumulative_filter_dict[key] = (
- utils.attr_as_boolean(filter_['value']))
+ filter_val = utils.attr_as_boolean(filter_['value'])
else:
_WontMatch.check(filter_['value'], col)
- cumulative_filter_dict[key] = filter_['value']
+ filter_val = filter_['value']
+
+ satisfied_filters.append(filter_)
+ return query.filter(col == filter_val)
try:
- filter_dict = {}
satisfied_filters = []
for filter_ in hints.filters:
if filter_['name'] not in model.attributes:
continue
if filter_['comparator'] == 'equals':
- exact_filter(model, filter_, filter_dict)
- satisfied_filters.append(filter_)
+ query = exact_filter(model, query, filter_,
+ satisfied_filters)
else:
query = inexact_filter(model, query, filter_,
satisfied_filters)
- # Apply any exact filters we built up
- if filter_dict:
- query = query.filter_by(**filter_dict)
-
# Remove satisfied filters, then the caller will know remaining filters
for filter_ in satisfied_filters:
hints.filters.remove(filter_)
@@ -377,7 +345,7 @@ def _limit(query, hints):
:param query: query to apply filters to
:param hints: contains the list of filters and limit details.
- :returns updated query
+ :returns: updated query
"""
# NOTE(henry-nash): If we were to implement pagination, then we
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/README b/keystone-moon/keystone/common/sql/migrate_repo/README
index 6218f8ca..4ea8dd4f 100644
--- a/keystone-moon/keystone/common/sql/migrate_repo/README
+++ b/keystone-moon/keystone/common/sql/migrate_repo/README
@@ -1,4 +1,4 @@
This is a database migration repository.
More information at
-http://code.google.com/p/sqlalchemy-migrate/
+https://git.openstack.org/cgit/openstack/sqlalchemy-migrate
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/__init__.py b/keystone-moon/keystone/common/sql/migrate_repo/__init__.py
index f73dfc12..e69de29b 100644
--- a/keystone-moon/keystone/common/sql/migrate_repo/__init__.py
+++ b/keystone-moon/keystone/common/sql/migrate_repo/__init__.py
@@ -1,17 +0,0 @@
-# Copyright 2014 Mirantis.inc
-# 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.
-
-
-DB_INIT_VERSION = 43
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/045_placeholder.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/045_placeholder.py
deleted file mode 100644
index 2a98fb90..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/045_placeholder.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# 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.
-
-# This is a placeholder for Icehouse backports. Do not use this number for new
-# Juno work. New Juno work starts after all the placeholders.
-#
-# See blueprint reserved-db-migrations-icehouse and the related discussion:
-# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
-
-
-def upgrade(migrate_engine):
- pass
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/046_placeholder.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/046_placeholder.py
deleted file mode 100644
index 2a98fb90..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/046_placeholder.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# 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.
-
-# This is a placeholder for Icehouse backports. Do not use this number for new
-# Juno work. New Juno work starts after all the placeholders.
-#
-# See blueprint reserved-db-migrations-icehouse and the related discussion:
-# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
-
-
-def upgrade(migrate_engine):
- pass
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/047_placeholder.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/047_placeholder.py
deleted file mode 100644
index 2a98fb90..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/047_placeholder.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# 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.
-
-# This is a placeholder for Icehouse backports. Do not use this number for new
-# Juno work. New Juno work starts after all the placeholders.
-#
-# See blueprint reserved-db-migrations-icehouse and the related discussion:
-# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
-
-
-def upgrade(migrate_engine):
- pass
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/049_placeholder.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/049_placeholder.py
deleted file mode 100644
index 2a98fb90..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/049_placeholder.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# 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.
-
-# This is a placeholder for Icehouse backports. Do not use this number for new
-# Juno work. New Juno work starts after all the placeholders.
-#
-# See blueprint reserved-db-migrations-icehouse and the related discussion:
-# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
-
-
-def upgrade(migrate_engine):
- pass
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/050_fk_consistent_indexes.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/050_fk_consistent_indexes.py
deleted file mode 100644
index c4b41580..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/050_fk_consistent_indexes.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2014 Mirantis.inc
-# 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
-
-
-def upgrade(migrate_engine):
-
- if migrate_engine.name == 'mysql':
- meta = sa.MetaData(bind=migrate_engine)
- endpoint = sa.Table('endpoint', meta, autoload=True)
-
- # NOTE(i159): MySQL requires indexes on referencing columns, and those
- # indexes create automatically. That those indexes will have different
- # names, depending on version of MySQL used. We shoud make this naming
- # consistent, by reverting index name to a consistent condition.
- if any(i for i in endpoint.indexes if
- list(i.columns.keys()) == ['service_id']
- and i.name != 'service_id'):
- # NOTE(i159): by this action will be made re-creation of an index
- # with the new name. This can be considered as renaming under the
- # MySQL rules.
- sa.Index('service_id', endpoint.c.service_id).create()
-
- user_group_membership = sa.Table('user_group_membership',
- meta, autoload=True)
-
- if any(i for i in user_group_membership.indexes if
- list(i.columns.keys()) == ['group_id']
- and i.name != 'group_id'):
- sa.Index('group_id', user_group_membership.c.group_id).create()
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/051_add_id_mapping.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/051_add_id_mapping.py
deleted file mode 100644
index 59720f6e..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/051_add_id_mapping.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2014 IBM Corp.
-#
-# 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 sql
-
-from keystone.identity.mapping_backends import mapping
-
-
-MAPPING_TABLE = 'id_mapping'
-
-
-def upgrade(migrate_engine):
- meta = sql.MetaData()
- meta.bind = migrate_engine
-
- mapping_table = sql.Table(
- MAPPING_TABLE,
- meta,
- sql.Column('public_id', sql.String(64), primary_key=True),
- sql.Column('domain_id', sql.String(64), nullable=False),
- sql.Column('local_id', sql.String(64), nullable=False),
- sql.Column('entity_type', sql.Enum(
- mapping.EntityType.USER,
- mapping.EntityType.GROUP,
- name='entity_type'),
- nullable=False),
- sql.UniqueConstraint('domain_id', 'local_id', 'entity_type'),
- mysql_engine='InnoDB',
- mysql_charset='utf8')
- mapping_table.create(migrate_engine, checkfirst=True)
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/052_add_auth_url_to_region.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/052_add_auth_url_to_region.py
deleted file mode 100644
index 86302a8f..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/052_add_auth_url_to_region.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2014 IBM Corp.
-#
-# 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 sql
-
-
-_REGION_TABLE_NAME = 'region'
-
-
-def upgrade(migrate_engine):
- meta = sql.MetaData()
- meta.bind = migrate_engine
-
- region_table = sql.Table(_REGION_TABLE_NAME, meta, autoload=True)
- url_column = sql.Column('url', sql.String(255), nullable=True)
- region_table.create_column(url_column)
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/053_endpoint_to_region_association.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/053_endpoint_to_region_association.py
deleted file mode 100644
index c2be48f4..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/053_endpoint_to_region_association.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# Copyright (c) 2013 Hewlett-Packard Development Company, L.P
-#
-# 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.
-
-"""Migrated the endpoint 'region' column to 'region_id.
-
-In addition to the rename, the new column is made a foreign key to the
-respective 'region' in the region table, ensuring that we auto-create
-any regions that are missing. Further, since the old region column
-was 255 chars, and the id column in the region table is 64 chars, the size
-of the id column in the region table is increased to match.
-
-To Upgrade:
-
-
-Region Table
-
-Increase the size of the if column in the region table
-
-Endpoint Table
-
-a. Add the endpoint region_id column, that is a foreign key to the region table
-b. For each endpoint
- i. Ensure there is matching region in region table, and if not, create it
- ii. Assign the id to the region_id column
-c. Remove the column region
-
-"""
-
-import migrate
-import sqlalchemy as sql
-from sqlalchemy.orm import sessionmaker
-
-
-def _migrate_to_region_id(migrate_engine, region_table, endpoint_table):
- endpoints = list(endpoint_table.select().execute())
-
- for endpoint in endpoints:
- if endpoint.region is None:
- continue
-
- region = list(region_table.select(
- whereclause=region_table.c.id == endpoint.region).execute())
- if len(region) == 1:
- region_id = region[0].id
- else:
- region_id = endpoint.region
- region = {'id': region_id,
- 'description': '',
- 'extra': '{}'}
- session = sessionmaker(bind=migrate_engine)()
- region_table.insert(region).execute()
- session.commit()
-
- new_values = {'region_id': region_id}
- f = endpoint_table.c.id == endpoint.id
- update = endpoint_table.update().where(f).values(new_values)
- migrate_engine.execute(update)
-
- migrate.ForeignKeyConstraint(
- columns=[endpoint_table.c.region_id],
- refcolumns=[region_table.c.id],
- name='fk_endpoint_region_id').create()
-
-
-def upgrade(migrate_engine):
- meta = sql.MetaData()
- meta.bind = migrate_engine
-
- region_table = sql.Table('region', meta, autoload=True)
- region_table.c.id.alter(type=sql.String(length=255))
- region_table.c.parent_region_id.alter(type=sql.String(length=255))
- endpoint_table = sql.Table('endpoint', meta, autoload=True)
- region_id_column = sql.Column('region_id',
- sql.String(length=255), nullable=True)
- region_id_column.create(endpoint_table)
-
- _migrate_to_region_id(migrate_engine, region_table, endpoint_table)
-
- endpoint_table.c.region.drop()
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/054_add_actor_id_index.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/054_add_actor_id_index.py
deleted file mode 100644
index caf4d66f..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/054_add_actor_id_index.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2014 IBM Corp.
-#
-# 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 sql
-
-
-ASSIGNMENT_TABLE = 'assignment'
-
-
-def upgrade(migrate_engine):
- meta = sql.MetaData()
- meta.bind = migrate_engine
-
- assignment = sql.Table(ASSIGNMENT_TABLE, meta, autoload=True)
- idx = sql.Index('ix_actor_id', assignment.c.actor_id)
- idx.create(migrate_engine)
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/055_add_indexes_to_token_table.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/055_add_indexes_to_token_table.py
deleted file mode 100644
index a7f327ea..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/055_add_indexes_to_token_table.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# 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 indexes to `user_id` and `trust_id` columns for the `token` table."""
-
-import sqlalchemy as sql
-
-
-def upgrade(migrate_engine):
- meta = sql.MetaData()
- meta.bind = migrate_engine
-
- token = sql.Table('token', meta, autoload=True)
-
- sql.Index('ix_token_user_id', token.c.user_id).create()
- sql.Index('ix_token_trust_id', token.c.trust_id).create()
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/060_placeholder.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/060_placeholder.py
deleted file mode 100644
index 8bb40490..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/060_placeholder.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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.
-
-# This is a placeholder for Juno backports. Do not use this number for new
-# Kilo work. New Kilo work starts after all the placeholders.
-
-
-def upgrade(migrate_engine):
- pass
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/061_add_parent_project.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/061_add_parent_project.py
deleted file mode 100644
index ca9b3ce2..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/061_add_parent_project.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# 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 sql
-
-from keystone.common.sql import migration_helpers
-
-
-_PROJECT_TABLE_NAME = 'project'
-_PARENT_ID_COLUMN_NAME = 'parent_id'
-
-
-def list_constraints(project_table):
- constraints = [{'table': project_table,
- 'fk_column': _PARENT_ID_COLUMN_NAME,
- 'ref_column': project_table.c.id}]
-
- return constraints
-
-
-def upgrade(migrate_engine):
- meta = sql.MetaData()
- meta.bind = migrate_engine
-
- project_table = sql.Table(_PROJECT_TABLE_NAME, meta, autoload=True)
- parent_id = sql.Column(_PARENT_ID_COLUMN_NAME, sql.String(64),
- nullable=True)
- project_table.create_column(parent_id)
-
- if migrate_engine.name == 'sqlite':
- return
- migration_helpers.add_constraints(list_constraints(project_table))
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/062_drop_assignment_role_fk.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/062_drop_assignment_role_fk.py
deleted file mode 100644
index f7a69bb6..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/062_drop_assignment_role_fk.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# 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
-
-from keystone.common.sql import migration_helpers
-
-
-def list_constraints(migrate_engine):
- meta = sqlalchemy.MetaData()
- meta.bind = migrate_engine
- assignment_table = sqlalchemy.Table('assignment', meta, autoload=True)
- role_table = sqlalchemy.Table('role', meta, autoload=True)
-
- constraints = [{'table': assignment_table,
- 'fk_column': 'role_id',
- 'ref_column': role_table.c.id}]
- return constraints
-
-
-def upgrade(migrate_engine):
- # SQLite does not support constraints, and querying the constraints
- # raises an exception
- if migrate_engine.name == 'sqlite':
- return
- migration_helpers.remove_constraints(list_constraints(migrate_engine))
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/063_drop_region_auth_url.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/063_drop_region_auth_url.py
deleted file mode 100644
index e45133ab..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/063_drop_region_auth_url.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# 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 sql
-
-
-_REGION_TABLE_NAME = 'region'
-
-
-def upgrade(migrate_engine):
- meta = sql.MetaData()
- meta.bind = migrate_engine
-
- region_table = sql.Table(_REGION_TABLE_NAME, meta, autoload=True)
- region_table.drop_column('url')
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/064_drop_user_and_group_fk.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/064_drop_user_and_group_fk.py
deleted file mode 100644
index 637f2151..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/064_drop_user_and_group_fk.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# 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
-
-from keystone.common.sql import migration_helpers
-
-
-def list_constraints(migrate_engine):
- meta = sqlalchemy.MetaData()
- meta.bind = migrate_engine
- user_table = sqlalchemy.Table('user', meta, autoload=True)
- group_table = sqlalchemy.Table('group', meta, autoload=True)
- domain_table = sqlalchemy.Table('domain', meta, autoload=True)
-
- constraints = [{'table': user_table,
- 'fk_column': 'domain_id',
- 'ref_column': domain_table.c.id},
- {'table': group_table,
- 'fk_column': 'domain_id',
- 'ref_column': domain_table.c.id}]
- return constraints
-
-
-def upgrade(migrate_engine):
- # SQLite does not support constraints, and querying the constraints
- # raises an exception
- if migrate_engine.name == 'sqlite':
- return
- migration_helpers.remove_constraints(list_constraints(migrate_engine))
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/065_add_domain_config.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/065_add_domain_config.py
deleted file mode 100644
index 63a86c11..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/065_add_domain_config.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# 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 sql
-
-from keystone.common import sql as ks_sql
-
-
-WHITELIST_TABLE = 'whitelisted_config'
-SENSITIVE_TABLE = 'sensitive_config'
-
-
-def upgrade(migrate_engine):
- meta = sql.MetaData()
- meta.bind = migrate_engine
-
- whitelist_table = sql.Table(
- WHITELIST_TABLE,
- meta,
- sql.Column('domain_id', sql.String(64), primary_key=True),
- sql.Column('group', sql.String(255), primary_key=True),
- sql.Column('option', sql.String(255), primary_key=True),
- sql.Column('value', ks_sql.JsonBlob.impl, nullable=False),
- mysql_engine='InnoDB',
- mysql_charset='utf8')
- whitelist_table.create(migrate_engine, checkfirst=True)
-
- sensitive_table = sql.Table(
- SENSITIVE_TABLE,
- meta,
- sql.Column('domain_id', sql.String(64), primary_key=True),
- sql.Column('group', sql.String(255), primary_key=True),
- sql.Column('option', sql.String(255), primary_key=True),
- sql.Column('value', ks_sql.JsonBlob.impl, nullable=False),
- mysql_engine='InnoDB',
- mysql_charset='utf8')
- sensitive_table.create(migrate_engine, checkfirst=True)
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/066_fixup_service_name_value.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/066_fixup_service_name_value.py
deleted file mode 100644
index fe0cee88..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/066_fixup_service_name_value.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# 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 oslo_serialization import jsonutils
-import sqlalchemy as sql
-
-
-def upgrade(migrate_engine):
- meta = sql.MetaData()
- meta.bind = migrate_engine
-
- service_table = sql.Table('service', meta, autoload=True)
- services = list(service_table.select().execute())
-
- for service in services:
- if service.extra is not None:
- extra_dict = jsonutils.loads(service.extra)
- else:
- extra_dict = {}
-
- # Skip records where service is not null
- if extra_dict.get('name') is not None:
- continue
- # Default the name to empty string
- extra_dict['name'] = ''
- new_values = {
- 'extra': jsonutils.dumps(extra_dict),
- }
- f = service_table.c.id == service.id
- update = service_table.update().where(f).values(new_values)
- migrate_engine.execute(update)
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/067_drop_redundant_mysql_index.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/067_drop_redundant_mysql_index.py
deleted file mode 100644
index b9df1a55..00000000
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/067_drop_redundant_mysql_index.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# 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
-
-
-def upgrade(migrate_engine):
- # NOTE(viktors): Migration 062 removed FK from `assignment` table, but
- # MySQL silently creates indexes on FK constraints, so we should remove
- # this index manually.
- if migrate_engine.name == 'mysql':
- meta = sqlalchemy.MetaData(bind=migrate_engine)
- table = sqlalchemy.Table('assignment', meta, autoload=True)
- for index in table.indexes:
- if [c.name for c in index.columns] == ['role_id']:
- index.drop(migrate_engine)
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/044_icehouse.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/067_kilo.py
index 6f326ecf..a6dbed67 100644
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/044_icehouse.py
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/067_kilo.py
@@ -12,18 +12,15 @@
import migrate
-from oslo_config import cfg
from oslo_log import log
import sqlalchemy as sql
-from sqlalchemy import orm
from keystone.assignment.backends import sql as assignment_sql
from keystone.common import sql as ks_sql
-from keystone.common.sql import migration_helpers
+from keystone.identity.mapping_backends import mapping as mapping_backend
LOG = log.getLogger(__name__)
-CONF = cfg.CONF
def upgrade(migrate_engine):
@@ -64,12 +61,12 @@ def upgrade(migrate_engine):
sql.Column('id', sql.String(length=64), primary_key=True),
sql.Column('legacy_endpoint_id', sql.String(length=64)),
sql.Column('interface', sql.String(length=8), nullable=False),
- sql.Column('region', sql.String(length=255)),
sql.Column('service_id', sql.String(length=64), nullable=False),
sql.Column('url', sql.Text, nullable=False),
sql.Column('extra', ks_sql.JsonBlob.impl),
sql.Column('enabled', sql.Boolean, nullable=False, default=True,
server_default='1'),
+ sql.Column('region_id', sql.String(length=255), nullable=True),
mysql_engine='InnoDB',
mysql_charset='utf8')
@@ -100,6 +97,7 @@ def upgrade(migrate_engine):
sql.Column('description', sql.Text),
sql.Column('enabled', sql.Boolean),
sql.Column('domain_id', sql.String(length=64), nullable=False),
+ sql.Column('parent_id', sql.String(64), nullable=True),
mysql_engine='InnoDB',
mysql_charset='utf8')
@@ -177,9 +175,9 @@ def upgrade(migrate_engine):
region = sql.Table(
'region',
meta,
- sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('id', sql.String(255), primary_key=True),
sql.Column('description', sql.String(255), nullable=False),
- sql.Column('parent_region_id', sql.String(64), nullable=True),
+ sql.Column('parent_region_id', sql.String(255), nullable=True),
sql.Column('extra', sql.Text()),
mysql_engine='InnoDB',
mysql_charset='utf8')
@@ -202,11 +200,45 @@ def upgrade(migrate_engine):
mysql_engine='InnoDB',
mysql_charset='utf8')
+ mapping = sql.Table(
+ 'id_mapping',
+ meta,
+ sql.Column('public_id', sql.String(64), primary_key=True),
+ sql.Column('domain_id', sql.String(64), nullable=False),
+ sql.Column('local_id', sql.String(64), nullable=False),
+ sql.Column('entity_type', sql.Enum(
+ mapping_backend.EntityType.USER,
+ mapping_backend.EntityType.GROUP,
+ name='entity_type'),
+ nullable=False),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+
+ domain_config_whitelist = sql.Table(
+ 'whitelisted_config',
+ meta,
+ sql.Column('domain_id', sql.String(64), primary_key=True),
+ sql.Column('group', sql.String(255), primary_key=True),
+ sql.Column('option', sql.String(255), primary_key=True),
+ sql.Column('value', ks_sql.JsonBlob.impl, nullable=False),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+
+ domain_config_sensitive = sql.Table(
+ 'sensitive_config',
+ meta,
+ sql.Column('domain_id', sql.String(64), primary_key=True),
+ sql.Column('group', sql.String(255), primary_key=True),
+ sql.Column('option', sql.String(255), primary_key=True),
+ sql.Column('value', ks_sql.JsonBlob.impl, nullable=False),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+
# create all tables
- tables = [credential, domain, endpoint, group,
- policy, project, role, service,
- token, trust, trust_role, user,
- user_group_membership, region, assignment]
+ tables = [credential, domain, endpoint, group, policy, project, role,
+ service, token, trust, trust_role, user, user_group_membership,
+ region, assignment, mapping, domain_config_whitelist,
+ domain_config_sensitive]
for table in tables:
try:
@@ -229,11 +261,22 @@ def upgrade(migrate_engine):
name='ixu_project_name_domain_id').create()
migrate.UniqueConstraint(domain.c.name,
name='ixu_domain_name').create()
+ migrate.UniqueConstraint(mapping.c.domain_id,
+ mapping.c.local_id,
+ mapping.c.entity_type,
+ name='domain_id').create()
# Indexes
sql.Index('ix_token_expires', token.c.expires).create()
sql.Index('ix_token_expires_valid', token.c.expires,
token.c.valid).create()
+ sql.Index('ix_actor_id', assignment.c.actor_id).create()
+ sql.Index('ix_token_user_id', token.c.user_id).create()
+ sql.Index('ix_token_trust_id', token.c.trust_id).create()
+ # NOTE(stevemar): The two indexes below were named 'service_id' and
+ # 'group_id' in 050_fk_consistent_indexes.py, and need to be preserved
+ sql.Index('service_id', endpoint.c.service_id).create()
+ sql.Index('group_id', user_group_membership.c.group_id).create()
fkeys = [
{'columns': [endpoint.c.service_id],
@@ -247,33 +290,28 @@ def upgrade(migrate_engine):
'references':[user.c.id],
'name': 'fk_user_group_membership_user_id'},
- {'columns': [user.c.domain_id],
- 'references': [domain.c.id],
- 'name': 'fk_user_domain_id'},
-
- {'columns': [group.c.domain_id],
- 'references': [domain.c.id],
- 'name': 'fk_group_domain_id'},
-
{'columns': [project.c.domain_id],
'references': [domain.c.id],
'name': 'fk_project_domain_id'},
- {'columns': [assignment.c.role_id],
- 'references': [role.c.id]}
+ {'columns': [endpoint.c.region_id],
+ 'references': [region.c.id],
+ 'name': 'fk_endpoint_region_id'},
+
+ {'columns': [project.c.parent_id],
+ 'references': [project.c.id],
+ 'name': 'project_parent_id_fkey'},
]
+ if migrate_engine.name == 'sqlite':
+ # NOTE(stevemar): We need to keep this FK constraint due to 073, but
+ # only for sqlite, once we collapse 073 we can remove this constraint
+ fkeys.append(
+ {'columns': [assignment.c.role_id],
+ 'references': [role.c.id],
+ 'name': 'fk_assignment_role_id'})
+
for fkey in fkeys:
migrate.ForeignKeyConstraint(columns=fkey['columns'],
refcolumns=fkey['references'],
name=fkey.get('name')).create()
-
- # Create the default domain.
- session = orm.sessionmaker(bind=migrate_engine)()
- domain.insert(migration_helpers.get_default_domain()).execute()
- session.commit()
-
-
-def downgrade(migrate_engine):
- raise NotImplementedError('Downgrade to pre-Icehouse release db schema is '
- 'unsupported.')
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/073_insert_assignment_inherited_pk.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/073_insert_assignment_inherited_pk.py
index ffa210c4..205f809e 100644
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/073_insert_assignment_inherited_pk.py
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/073_insert_assignment_inherited_pk.py
@@ -18,7 +18,7 @@ from keystone.assignment.backends import sql as assignment_sql
def upgrade(migrate_engine):
- """Inserts inherited column to assignment table PK contraints.
+ """Inserts inherited column to assignment table PK constraints.
For non-SQLite databases, it changes the constraint in the existing table.
@@ -26,7 +26,6 @@ def upgrade(migrate_engine):
assignment table with the new PK constraint and migrates the existing data.
"""
-
ASSIGNMENT_TABLE_NAME = 'assignment'
metadata = sql.MetaData()
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/056_placeholder.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/076_placeholder.py
index 8bb40490..9f6e8415 100644
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/056_placeholder.py
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/076_placeholder.py
@@ -10,8 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-# This is a placeholder for Juno backports. Do not use this number for new
-# Kilo work. New Kilo work starts after all the placeholders.
+# This is a placeholder for Liberty backports. Do not use this number for new
+# Mitaka work. New Mitaka work starts after all the placeholders.
def upgrade(migrate_engine):
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/057_placeholder.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/077_placeholder.py
index 8bb40490..9f6e8415 100644
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/057_placeholder.py
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/077_placeholder.py
@@ -10,8 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-# This is a placeholder for Juno backports. Do not use this number for new
-# Kilo work. New Kilo work starts after all the placeholders.
+# This is a placeholder for Liberty backports. Do not use this number for new
+# Mitaka work. New Mitaka work starts after all the placeholders.
def upgrade(migrate_engine):
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/058_placeholder.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/078_placeholder.py
index 8bb40490..9f6e8415 100644
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/058_placeholder.py
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/078_placeholder.py
@@ -10,8 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-# This is a placeholder for Juno backports. Do not use this number for new
-# Kilo work. New Kilo work starts after all the placeholders.
+# This is a placeholder for Liberty backports. Do not use this number for new
+# Mitaka work. New Mitaka work starts after all the placeholders.
def upgrade(migrate_engine):
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/059_placeholder.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/079_placeholder.py
index 8bb40490..9f6e8415 100644
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/059_placeholder.py
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/079_placeholder.py
@@ -10,8 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-# This is a placeholder for Juno backports. Do not use this number for new
-# Kilo work. New Kilo work starts after all the placeholders.
+# This is a placeholder for Liberty backports. Do not use this number for new
+# Mitaka work. New Mitaka work starts after all the placeholders.
def upgrade(migrate_engine):
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/080_placeholder.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/080_placeholder.py
new file mode 100644
index 00000000..9f6e8415
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/080_placeholder.py
@@ -0,0 +1,18 @@
+# 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.
+
+# This is a placeholder for Liberty backports. Do not use this number for new
+# Mitaka work. New Mitaka work starts after all the placeholders.
+
+
+def upgrade(migrate_engine):
+ pass
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/081_add_endpoint_policy_table.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/081_add_endpoint_policy_table.py
new file mode 100644
index 00000000..a0c307d0
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/081_add_endpoint_policy_table.py
@@ -0,0 +1,54 @@
+# Copyright 2014 IBM Corp.
+#
+# 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 sql
+
+from keystone.common.sql import migration_helpers
+
+
+def upgrade(migrate_engine):
+ try:
+ extension_version = migration_helpers.get_db_version(
+ extension='endpoint_policy',
+ engine=migrate_engine)
+ except Exception:
+ extension_version = 0
+
+ # This migration corresponds to endpoint_policy extension migration 1. Only
+ # update if it has not been run.
+ if extension_version >= 1:
+ return
+
+ # Upgrade operations go here. Don't create your own engine; bind
+ # migrate_engine to your metadata
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ endpoint_policy_table = sql.Table(
+ 'policy_association',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('policy_id', sql.String(64),
+ nullable=False),
+ sql.Column('endpoint_id', sql.String(64),
+ nullable=True),
+ sql.Column('service_id', sql.String(64),
+ nullable=True),
+ sql.Column('region_id', sql.String(64),
+ nullable=True),
+ sql.UniqueConstraint('endpoint_id', 'service_id', 'region_id'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+
+ endpoint_policy_table.create(migrate_engine, checkfirst=True)
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/082_add_federation_tables.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/082_add_federation_tables.py
new file mode 100644
index 00000000..7e426373
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/082_add_federation_tables.py
@@ -0,0 +1,97 @@
+# Copyright 2014 IBM Corp.
+#
+# 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 oslo_config import cfg
+import sqlalchemy as sql
+
+from keystone.common.sql import migration_helpers
+
+CONF = cfg.CONF
+_RELAY_STATE_PREFIX = 'relay_state_prefix'
+
+
+def upgrade(migrate_engine):
+ try:
+ extension_version = migration_helpers.get_db_version(
+ extension='federation',
+ engine=migrate_engine)
+ except Exception:
+ extension_version = 0
+
+ # This migration corresponds to federation extension migration 8. Only
+ # update if it has not been run.
+ if extension_version >= 8:
+ return
+
+ # Upgrade operations go here. Don't create your own engine; bind
+ # migrate_engine to your metadata
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ idp_table = sql.Table(
+ 'identity_provider',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('enabled', sql.Boolean, nullable=False),
+ sql.Column('description', sql.Text(), nullable=True),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ idp_table.create(migrate_engine, checkfirst=True)
+
+ federation_protocol_table = sql.Table(
+ 'federation_protocol',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('idp_id', sql.String(64),
+ sql.ForeignKey('identity_provider.id', ondelete='CASCADE'),
+ primary_key=True),
+ sql.Column('mapping_id', sql.String(64), nullable=False),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ federation_protocol_table.create(migrate_engine, checkfirst=True)
+
+ mapping_table = sql.Table(
+ 'mapping',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('rules', sql.Text(), nullable=False),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ mapping_table.create(migrate_engine, checkfirst=True)
+
+ relay_state_prefix_default = CONF.saml.relay_state_prefix
+ sp_table = sql.Table(
+ 'service_provider',
+ meta,
+ sql.Column('auth_url', sql.String(256), nullable=False),
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('enabled', sql.Boolean, nullable=False),
+ sql.Column('description', sql.Text(), nullable=True),
+ sql.Column('sp_url', sql.String(256), nullable=False),
+ sql.Column(_RELAY_STATE_PREFIX, sql.String(256), nullable=False,
+ server_default=relay_state_prefix_default),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ sp_table.create(migrate_engine, checkfirst=True)
+
+ idp_table = sql.Table('identity_provider', meta, autoload=True)
+ remote_id_table = sql.Table(
+ 'idp_remote_ids',
+ meta,
+ sql.Column('idp_id', sql.String(64),
+ sql.ForeignKey('identity_provider.id', ondelete='CASCADE')),
+ sql.Column('remote_id', sql.String(255), primary_key=True),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ remote_id_table.create(migrate_engine, checkfirst=True)
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/083_add_oauth1_tables.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/083_add_oauth1_tables.py
new file mode 100644
index 00000000..5a859b4b
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/083_add_oauth1_tables.py
@@ -0,0 +1,75 @@
+# Copyright 2014 IBM Corp.
+#
+# 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 sql
+
+from keystone.common.sql import migration_helpers
+
+
+def upgrade(migrate_engine):
+ try:
+ extension_version = migration_helpers.get_db_version(
+ extension='oauth1',
+ engine=migrate_engine)
+ except Exception:
+ extension_version = 0
+
+ # This migration corresponds to oauth extension migration 5. Only
+ # update if it has not been run.
+ if extension_version >= 5:
+ return
+
+ # Upgrade operations go here. Don't create your own engine; bind
+ # migrate_engine to your metadata
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ consumer_table = sql.Table(
+ 'consumer',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True, nullable=False),
+ sql.Column('description', sql.String(64), nullable=True),
+ sql.Column('secret', sql.String(64), nullable=False),
+ sql.Column('extra', sql.Text(), nullable=False))
+ consumer_table.create(migrate_engine, checkfirst=True)
+
+ request_token_table = sql.Table(
+ 'request_token',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True, nullable=False),
+ sql.Column('request_secret', sql.String(64), nullable=False),
+ sql.Column('verifier', sql.String(64), nullable=True),
+ sql.Column('authorizing_user_id', sql.String(64), nullable=True),
+ sql.Column('requested_project_id', sql.String(64), nullable=False),
+ sql.Column('role_ids', sql.Text(), nullable=True),
+ sql.Column('consumer_id', sql.String(64),
+ sql.ForeignKey('consumer.id'),
+ nullable=False, index=True),
+ sql.Column('expires_at', sql.String(64), nullable=True))
+ request_token_table.create(migrate_engine, checkfirst=True)
+
+ access_token_table = sql.Table(
+ 'access_token',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True, nullable=False),
+ sql.Column('access_secret', sql.String(64), nullable=False),
+ sql.Column('authorizing_user_id', sql.String(64),
+ nullable=False, index=True),
+ sql.Column('project_id', sql.String(64), nullable=False),
+ sql.Column('role_ids', sql.Text(), nullable=False),
+ sql.Column('consumer_id', sql.String(64),
+ sql.ForeignKey('consumer.id'),
+ nullable=False, index=True),
+ sql.Column('expires_at', sql.String(64), nullable=True))
+ access_token_table.create(migrate_engine, checkfirst=True)
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/084_add_revoke_tables.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/084_add_revoke_tables.py
new file mode 100644
index 00000000..1a28a53c
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/084_add_revoke_tables.py
@@ -0,0 +1,55 @@
+# Copyright 2014 IBM Corp.
+#
+# 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 sql
+
+from keystone.common.sql import migration_helpers
+
+
+def upgrade(migrate_engine):
+ try:
+ extension_version = migration_helpers.get_db_version(
+ extension='revoke',
+ engine=migrate_engine)
+ except Exception:
+ extension_version = 0
+
+ # This migration corresponds to revoke extension migration 2. Only
+ # update if it has not been run.
+ if extension_version >= 2:
+ return
+
+ # Upgrade operations go here. Don't create your own engine; bind
+ # migrate_engine to your metadata
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ service_table = sql.Table(
+ 'revocation_event',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('domain_id', sql.String(64)),
+ sql.Column('project_id', sql.String(64)),
+ sql.Column('user_id', sql.String(64)),
+ sql.Column('role_id', sql.String(64)),
+ sql.Column('trust_id', sql.String(64)),
+ sql.Column('consumer_id', sql.String(64)),
+ sql.Column('access_token_id', sql.String(64)),
+ sql.Column('issued_before', sql.DateTime(), nullable=False),
+ sql.Column('expires_at', sql.DateTime()),
+ sql.Column('revoked_at', sql.DateTime(), index=True, nullable=False),
+ sql.Column('audit_id', sql.String(32), nullable=True),
+ sql.Column('audit_chain_id', sql.String(32), nullable=True))
+
+ service_table.create(migrate_engine, checkfirst=True)
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/085_add_endpoint_filtering_table.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/085_add_endpoint_filtering_table.py
new file mode 100644
index 00000000..5790bd98
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/085_add_endpoint_filtering_table.py
@@ -0,0 +1,70 @@
+# 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 sql
+
+from keystone.common.sql import migration_helpers
+
+
+def upgrade(migrate_engine):
+ try:
+ extension_version = migration_helpers.get_db_version(
+ extension='endpoint_filter',
+ engine=migrate_engine)
+ except Exception:
+ extension_version = 0
+
+ # This migration corresponds to endpoint_filter extension migration 2. Only
+ # update if it has not been run.
+ if extension_version >= 2:
+ return
+
+ # Upgrade operations go here. Don't create your own engine; bind
+ # migrate_engine to your metadata
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ EP_GROUP_ID = 'endpoint_group_id'
+ PROJECT_ID = 'project_id'
+
+ endpoint_filtering_table = sql.Table(
+ 'project_endpoint',
+ meta,
+ sql.Column(
+ 'endpoint_id',
+ sql.String(64),
+ primary_key=True,
+ nullable=False),
+ sql.Column(
+ 'project_id',
+ sql.String(64),
+ primary_key=True,
+ nullable=False))
+ endpoint_filtering_table.create(migrate_engine, checkfirst=True)
+
+ endpoint_group_table = sql.Table(
+ 'endpoint_group',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(255), nullable=False),
+ sql.Column('description', sql.Text, nullable=True),
+ sql.Column('filters', sql.Text(), nullable=False))
+ endpoint_group_table.create(migrate_engine, checkfirst=True)
+
+ project_endpoint_group_table = sql.Table(
+ 'project_endpoint_group',
+ meta,
+ sql.Column(EP_GROUP_ID, sql.String(64),
+ sql.ForeignKey('endpoint_group.id'), nullable=False),
+ sql.Column(PROJECT_ID, sql.String(64), nullable=False),
+ sql.PrimaryKeyConstraint(EP_GROUP_ID, PROJECT_ID))
+ project_endpoint_group_table.create(migrate_engine, checkfirst=True)
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/048_placeholder.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/086_add_duplicate_constraint_trusts.py
index 2a98fb90..2b115ea4 100644
--- a/keystone-moon/keystone/common/sql/migrate_repo/versions/048_placeholder.py
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/086_add_duplicate_constraint_trusts.py
@@ -1,3 +1,6 @@
+# Copyright 2015 Intel Corporation
+# 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
@@ -10,12 +13,14 @@
# License for the specific language governing permissions and limitations
# under the License.
-# This is a placeholder for Icehouse backports. Do not use this number for new
-# Juno work. New Juno work starts after all the placeholders.
-#
-# See blueprint reserved-db-migrations-icehouse and the related discussion:
-# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
+from migrate import UniqueConstraint
+from sqlalchemy import MetaData, Table
def upgrade(migrate_engine):
- pass
+ meta = MetaData(bind=migrate_engine)
+ trusts = Table('trust', meta, autoload=True)
+
+ UniqueConstraint('trustor_user_id', 'trustee_user_id', 'project_id',
+ 'impersonation', 'expires_at', table=trusts,
+ name='duplicate_trust_constraint').create()
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/087_implied_roles.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/087_implied_roles.py
new file mode 100644
index 00000000..7713ce8f
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/087_implied_roles.py
@@ -0,0 +1,43 @@
+# 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 migrate
+import sqlalchemy as sql
+
+
+ROLE_TABLE = 'role'
+
+
+def upgrade(migrate_engine):
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ implied_role = sql.Table(
+ 'implied_role', meta,
+ sql.Column('prior_role_id', sql.String(length=64), primary_key=True),
+ sql.Column(
+ 'implied_role_id', sql.String(length=64), primary_key=True),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ implied_role.create()
+ role = sql.Table(ROLE_TABLE, meta, autoload=True)
+ fkeys = [
+ {'columns': [implied_role.c.prior_role_id],
+ 'references': [role.c.id]},
+ {'columns': [implied_role.c.implied_role_id],
+ 'references': [role.c.id]},
+ ]
+ for fkey in fkeys:
+ migrate.ForeignKeyConstraint(columns=fkey['columns'],
+ refcolumns=fkey['references'],
+ name=fkey.get('name')).create()
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/088_domain_specific_roles.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/088_domain_specific_roles.py
new file mode 100644
index 00000000..8b792dfa
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/088_domain_specific_roles.py
@@ -0,0 +1,60 @@
+# 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 migrate
+import sqlalchemy as sql
+
+
+_ROLE_NAME_NEW_CONSTRAINT = 'ixu_role_name_domain_id'
+_ROLE_TABLE_NAME = 'role'
+_ROLE_NAME_COLUMN_NAME = 'name'
+_DOMAIN_ID_COLUMN_NAME = 'domain_id'
+_NULL_DOMAIN_ID = '<<null>>'
+
+
+def upgrade(migrate_engine):
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ role_table = sql.Table(_ROLE_TABLE_NAME, meta, autoload=True)
+ domain_id = sql.Column(_DOMAIN_ID_COLUMN_NAME, sql.String(64),
+ nullable=False, server_default=_NULL_DOMAIN_ID)
+
+ # NOTE(morganfainberg): the `role_name` unique constraint is not
+ # guaranteed to be a fixed name, such as 'ixu_role_name`, so we need to
+ # search for the correct constraint that only affects role_table.c.name
+ # and drop that constraint.
+ to_drop = None
+ if migrate_engine.name == 'mysql':
+ for c in role_table.indexes:
+ if (c.unique and len(c.columns) == 1 and
+ _ROLE_NAME_COLUMN_NAME in c.columns):
+ to_drop = c
+ break
+ else:
+ for c in role_table.constraints:
+ if len(c.columns) == 1 and _ROLE_NAME_COLUMN_NAME in c.columns:
+ to_drop = c
+ break
+
+ if to_drop is not None:
+ migrate.UniqueConstraint(role_table.c.name,
+ name=to_drop.name).drop()
+
+ # perform changes after constraint is dropped.
+ if 'domain_id' not in role_table.columns:
+ # Only create the column if it doesn't already exist.
+ role_table.create_column(domain_id)
+
+ migrate.UniqueConstraint(role_table.c.name,
+ role_table.c.domain_id,
+ name=_ROLE_NAME_NEW_CONSTRAINT).create()
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/089_add_root_of_all_domains.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/089_add_root_of_all_domains.py
new file mode 100644
index 00000000..477c719a
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/089_add_root_of_all_domains.py
@@ -0,0 +1,76 @@
+# 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 sql
+
+
+_PROJECT_TABLE_NAME = 'project'
+_DOMAIN_TABLE_NAME = 'domain'
+NULL_DOMAIN_ID = '<<keystone.domain.root>>'
+
+
+def upgrade(migrate_engine):
+
+ def _generate_root_domain_project():
+ # Generate a project that will act as a root for all domains, in order
+ # for use to be able to use a FK constraint on domain_id. Projects
+ # acting as a domain will not reference this as their parent_id, just
+ # as domain_id.
+ #
+ # This special project is filtered out by the driver, so is never
+ # visible to the manager or API.
+
+ project_ref = {
+ 'id': NULL_DOMAIN_ID,
+ 'name': NULL_DOMAIN_ID,
+ 'enabled': False,
+ 'description': '',
+ 'domain_id': NULL_DOMAIN_ID,
+ 'is_domain': True,
+ 'parent_id': None,
+ 'extra': '{}'
+ }
+ return project_ref
+
+ def _generate_root_domain():
+ # Generate a similar root for the domain table, this is an interim
+ # step so as to allow continuation of current project domain_id FK.
+ #
+ # This special domain is filtered out by the driver, so is never
+ # visible to the manager or API.
+
+ domain_ref = {
+ 'id': NULL_DOMAIN_ID,
+ 'name': NULL_DOMAIN_ID,
+ 'enabled': False,
+ 'extra': '{}'
+ }
+ return domain_ref
+
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+ session = sql.orm.sessionmaker(bind=migrate_engine)()
+
+ project_table = sql.Table(_PROJECT_TABLE_NAME, meta, autoload=True)
+ domain_table = sql.Table(_DOMAIN_TABLE_NAME, meta, autoload=True)
+
+ root_domain = _generate_root_domain()
+ new_entry = domain_table.insert().values(**root_domain)
+ session.execute(new_entry)
+ session.commit()
+
+ root_domain_project = _generate_root_domain_project()
+ new_entry = project_table.insert().values(**root_domain_project)
+ session.execute(new_entry)
+ session.commit()
+
+ session.close()
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/090_add_local_user_and_password_tables.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/090_add_local_user_and_password_tables.py
new file mode 100644
index 00000000..800ba47e
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/090_add_local_user_and_password_tables.py
@@ -0,0 +1,42 @@
+# 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 sql
+
+
+def upgrade(migrate_engine):
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ user = sql.Table('user', meta, autoload=True)
+
+ local_user = sql.Table(
+ 'local_user',
+ meta,
+ sql.Column('id', sql.Integer, primary_key=True, nullable=False),
+ sql.Column('user_id', sql.String(64),
+ sql.ForeignKey(user.c.id, ondelete='CASCADE'),
+ nullable=False, unique=True),
+ sql.Column('domain_id', sql.String(64), nullable=False),
+ sql.Column('name', sql.String(255), nullable=False),
+ sql.UniqueConstraint('domain_id', 'name'))
+ local_user.create(migrate_engine, checkfirst=True)
+
+ password = sql.Table(
+ 'password',
+ meta,
+ sql.Column('id', sql.Integer, primary_key=True, nullable=False),
+ sql.Column('local_user_id', sql.Integer,
+ sql.ForeignKey(local_user.c.id, ondelete='CASCADE'),
+ nullable=False),
+ sql.Column('password', sql.String(128), nullable=False))
+ password.create(migrate_engine, checkfirst=True)
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/091_migrate_data_to_local_user_and_password_tables.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/091_migrate_data_to_local_user_and_password_tables.py
new file mode 100644
index 00000000..1f41fd89
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/091_migrate_data_to_local_user_and_password_tables.py
@@ -0,0 +1,66 @@
+# 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 migrate
+import sqlalchemy as sql
+from sqlalchemy import func
+
+
+def upgrade(migrate_engine):
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ user_table = sql.Table('user', meta, autoload=True)
+ local_user_table = sql.Table('local_user', meta, autoload=True)
+ password_table = sql.Table('password', meta, autoload=True)
+
+ # migrate data to local_user table
+ local_user_values = []
+ for row in user_table.select().execute():
+ # skip the row that already exists in `local_user`, this could
+ # happen if run into a partially-migrated table due to the
+ # bug #1549705.
+ filter_by = local_user_table.c.user_id == row['id']
+ user_count = sql.select([func.count()]).select_from(
+ local_user_table).where(filter_by).execute().fetchone()[0]
+ if user_count == 0:
+ local_user_values.append({'user_id': row['id'],
+ 'domain_id': row['domain_id'],
+ 'name': row['name']})
+ if local_user_values:
+ local_user_table.insert().values(local_user_values).execute()
+
+ # migrate data to password table
+ sel = (
+ sql.select([user_table, local_user_table], use_labels=True)
+ .select_from(user_table.join(local_user_table, user_table.c.id ==
+ local_user_table.c.user_id))
+ )
+ user_rows = sel.execute()
+ password_values = []
+ for row in user_rows:
+ if row['user_password']:
+ password_values.append({'local_user_id': row['local_user_id'],
+ 'password': row['user_password']})
+ if password_values:
+ password_table.insert().values(password_values).execute()
+
+ # remove domain_id and name unique constraint
+ if migrate_engine.name != 'sqlite':
+ migrate.UniqueConstraint(user_table.c.domain_id,
+ user_table.c.name,
+ name='ixu_user_name_domain_id').drop()
+
+ # drop user columns
+ user_table.c.domain_id.drop()
+ user_table.c.name.drop()
+ user_table.c.password.drop()
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/092_make_implied_roles_fks_cascaded.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/092_make_implied_roles_fks_cascaded.py
new file mode 100644
index 00000000..5e841899
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/092_make_implied_roles_fks_cascaded.py
@@ -0,0 +1,46 @@
+# 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 migrate
+import sqlalchemy as sql
+
+
+ROLE_TABLE = 'role'
+IMPLIED_ROLE_TABLE = 'implied_role'
+
+
+def upgrade(migrate_engine):
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ role = sql.Table(ROLE_TABLE, meta, autoload=True)
+ implied_role = sql.Table(IMPLIED_ROLE_TABLE, meta, autoload=True)
+
+ fkeys = [
+ {'columns': [implied_role.c.prior_role_id],
+ 'references': [role.c.id]},
+ {'columns': [implied_role.c.implied_role_id],
+ 'references': [role.c.id]},
+ ]
+
+ # NOTE(stevemar): We need to divide these into two separate loops otherwise
+ # they may clobber each other and only end up with one foreign key.
+ for fkey in fkeys:
+ migrate.ForeignKeyConstraint(columns=fkey['columns'],
+ refcolumns=fkey['references'],
+ name=fkey.get('name')).drop()
+ for fkey in fkeys:
+ migrate.ForeignKeyConstraint(columns=fkey['columns'],
+ refcolumns=fkey['references'],
+ name=fkey.get('name'),
+ ondelete="CASCADE").create()
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/093_migrate_domains_to_projects.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/093_migrate_domains_to_projects.py
new file mode 100644
index 00000000..f6bba7d9
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/093_migrate_domains_to_projects.py
@@ -0,0 +1,125 @@
+# 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 json
+
+import sqlalchemy as sql
+
+from keystone.common.sql import migration_helpers
+
+
+_PROJECT_TABLE_NAME = 'project'
+_DOMAIN_TABLE_NAME = 'domain'
+_PARENT_ID_COLUMN_NAME = 'parent_id'
+_DOMAIN_ID_COLUMN_NAME = 'domain_id'
+
+# Above the driver level, the domain_id of a project acting as a domain is
+# None. However, in order to enable sql integrity constraints to still operate
+# on this column, we create a special "root of all domains" row, with an ID of
+# NULL_DOMAIN_ID, which all projects acting as a domain reference in their
+# domain_id attribute. This special row, as well as NULL_DOMAIN_ID, are never
+# exposed outside of sql driver layer.
+NULL_DOMAIN_ID = '<<keystone.domain.root>>'
+
+
+def list_existing_project_constraints(project_table, domain_table):
+ constraints = [{'table': project_table,
+ 'fk_column': _PARENT_ID_COLUMN_NAME,
+ 'ref_column': project_table.c.id},
+ {'table': project_table,
+ 'fk_column': _DOMAIN_ID_COLUMN_NAME,
+ 'ref_column': domain_table.c.id}]
+
+ return constraints
+
+
+def list_new_project_constraints(project_table):
+ constraints = [{'table': project_table,
+ 'fk_column': _PARENT_ID_COLUMN_NAME,
+ 'ref_column': project_table.c.id},
+ {'table': project_table,
+ 'fk_column': _DOMAIN_ID_COLUMN_NAME,
+ 'ref_column': project_table.c.id}]
+
+ return constraints
+
+
+def upgrade(migrate_engine):
+
+ def _project_from_domain(domain):
+ # Creates a project dict with is_domain=True from the provided
+ # domain.
+
+ description = None
+ extra = {}
+ if domain.extra is not None:
+ # 'description' property is an extra attribute in domains but a
+ # first class attribute in projects
+ extra = json.loads(domain.extra)
+ description = extra.pop('description', None)
+
+ return {
+ 'id': domain.id,
+ 'name': domain.name,
+ 'enabled': domain.enabled,
+ 'description': description,
+ 'domain_id': NULL_DOMAIN_ID,
+ 'is_domain': True,
+ 'parent_id': None,
+ 'extra': json.dumps(extra)
+ }
+
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+ session = sql.orm.sessionmaker(bind=migrate_engine)()
+
+ project_table = sql.Table(_PROJECT_TABLE_NAME, meta, autoload=True)
+ domain_table = sql.Table(_DOMAIN_TABLE_NAME, meta, autoload=True)
+
+ # NOTE(htruta): Remove the parent_id constraint during the migration
+ # because for every root project inside this domain, we will set
+ # the project domain_id to be its parent_id. We re-enable the constraint
+ # in the end of this method. We also remove the domain_id constraint,
+ # while be recreated a FK to the project_id at the end.
+ migration_helpers.remove_constraints(
+ list_existing_project_constraints(project_table, domain_table))
+
+ # For each domain, create a project acting as a domain. We ignore the
+ # "root of all domains" row, since we already have one of these in the
+ # project table.
+ domains = list(domain_table.select().execute())
+ for domain in domains:
+ if domain.id == NULL_DOMAIN_ID:
+ continue
+ is_domain_project = _project_from_domain(domain)
+ new_entry = project_table.insert().values(**is_domain_project)
+ session.execute(new_entry)
+ session.commit()
+
+ # For each project, that has no parent (i.e. a top level project), update
+ # it's parent_id to point at the project acting as its domain. We ignore
+ # the "root of all domains" row, since its parent_id must always be None.
+ projects = list(project_table.select().execute())
+ for project in projects:
+ if (project.parent_id is not None or project.is_domain or
+ project.id == NULL_DOMAIN_ID):
+ continue
+ values = {'parent_id': project.domain_id}
+ update = project_table.update().where(
+ project_table.c.id == project.id).values(values)
+ session.execute(update)
+ session.commit()
+
+ migration_helpers.add_constraints(
+ list_new_project_constraints(project_table))
+
+ session.close()
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/094_add_federated_user_table.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/094_add_federated_user_table.py
new file mode 100644
index 00000000..6fd3f051
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/094_add_federated_user_table.py
@@ -0,0 +1,43 @@
+# 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 migrate
+import sqlalchemy as sql
+
+
+def upgrade(migrate_engine):
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ user_table = sql.Table('user', meta, autoload=True)
+ idp_table = sql.Table('identity_provider', meta, autoload=True)
+ protocol_table = sql.Table('federation_protocol', meta, autoload=True)
+
+ federated_table = sql.Table(
+ 'federated_user',
+ meta,
+ sql.Column('id', sql.Integer, primary_key=True, nullable=False),
+ sql.Column('user_id', sql.String(64),
+ sql.ForeignKey(user_table.c.id, ondelete='CASCADE'),
+ nullable=False),
+ sql.Column('idp_id', sql.String(64),
+ sql.ForeignKey(idp_table.c.id, ondelete='CASCADE'),
+ nullable=False),
+ sql.Column('protocol_id', sql.String(64), nullable=False),
+ sql.Column('unique_id', sql.String(255), nullable=False),
+ sql.Column('display_name', sql.String(255), nullable=True),
+ sql.UniqueConstraint('idp_id', 'protocol_id', 'unique_id'))
+ federated_table.create(migrate_engine, checkfirst=True)
+
+ migrate.ForeignKeyConstraint(
+ columns=[federated_table.c.protocol_id, federated_table.c.idp_id],
+ refcolumns=[protocol_table.c.id, protocol_table.c.idp_id]).create()
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/095_add_integer_pkey_to_revocation_event_table.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/095_add_integer_pkey_to_revocation_event_table.py
new file mode 100644
index 00000000..7a75f7b1
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/095_add_integer_pkey_to_revocation_event_table.py
@@ -0,0 +1,62 @@
+# 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 sql
+
+
+def upgrade(migrate_engine):
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ # You can specify primary keys when creating tables, however adding
+ # auto-increment integer primary keys for existing tables is not
+ # cross-engine compatibility supported. Thus, the approach is to:
+ # (1) create a new revocation_event table with an int pkey,
+ # (2) migrate data from the old table to the new table,
+ # (3) delete the old revocation_event table
+ # (4) rename the new revocation_event table
+ revocation_table = sql.Table('revocation_event', meta, autoload=True)
+
+ revocation_table_new = sql.Table(
+ 'revocation_event_new',
+ meta,
+ sql.Column('id', sql.Integer, primary_key=True),
+ sql.Column('domain_id', sql.String(64)),
+ sql.Column('project_id', sql.String(64)),
+ sql.Column('user_id', sql.String(64)),
+ sql.Column('role_id', sql.String(64)),
+ sql.Column('trust_id', sql.String(64)),
+ sql.Column('consumer_id', sql.String(64)),
+ sql.Column('access_token_id', sql.String(64)),
+ sql.Column('issued_before', sql.DateTime(), nullable=False),
+ sql.Column('expires_at', sql.DateTime()),
+ sql.Column('revoked_at', sql.DateTime(), index=True, nullable=False),
+ sql.Column('audit_id', sql.String(32), nullable=True),
+ sql.Column('audit_chain_id', sql.String(32), nullable=True))
+ revocation_table_new.create(migrate_engine, checkfirst=True)
+
+ revocation_table_new.insert().from_select(['domain_id',
+ 'project_id',
+ 'user_id',
+ 'role_id',
+ 'trust_id',
+ 'consumer_id',
+ 'access_token_id',
+ 'issued_before',
+ 'expires_at',
+ 'revoked_at',
+ 'audit_id',
+ 'audit_chain_id'],
+ revocation_table.select())
+
+ revocation_table.drop()
+ revocation_table_new.rename('revocation_event')
diff --git a/keystone-moon/keystone/common/sql/migrate_repo/versions/096_drop_role_name_constraint.py b/keystone-moon/keystone/common/sql/migrate_repo/versions/096_drop_role_name_constraint.py
new file mode 100644
index 00000000..0156de21
--- /dev/null
+++ b/keystone-moon/keystone/common/sql/migrate_repo/versions/096_drop_role_name_constraint.py
@@ -0,0 +1,50 @@
+# 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 migrate
+import sqlalchemy as sql
+
+_ROLE_TABLE_NAME = 'role'
+_ROLE_NAME_COLUMN_NAME = 'name'
+
+
+def upgrade(migrate_engine):
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ role_table = sql.Table(_ROLE_TABLE_NAME, meta, autoload=True)
+
+ # NOTE(morganfainberg): the `role_name` unique constraint is not
+ # guaranteed to be named 'ixu_role_name', so we need to search for the
+ # correct constraint that only affects role_table.c.name and drop
+ # that constraint.
+ #
+ # This is an idempotent change that reflects the fix to migration
+ # 88 if the role_name unique constraint was not named consistently and
+ # someone manually fixed the migrations / db without dropping the
+ # old constraint.
+ to_drop = None
+ if migrate_engine.name == 'mysql':
+ for c in role_table.indexes:
+ if (c.unique and len(c.columns) == 1 and
+ _ROLE_NAME_COLUMN_NAME in c.columns):
+ to_drop = c
+ break
+ else:
+ for c in role_table.constraints:
+ if len(c.columns) == 1 and _ROLE_NAME_COLUMN_NAME in c.columns:
+ to_drop = c
+ break
+
+ if to_drop is not None:
+ migrate.UniqueConstraint(role_table.c.name,
+ name=to_drop.name).drop()
diff --git a/keystone-moon/keystone/common/sql/migration_helpers.py b/keystone-moon/keystone/common/sql/migration_helpers.py
index aaa59f70..40c1fbb5 100644
--- a/keystone-moon/keystone/common/sql/migration_helpers.py
+++ b/keystone-moon/keystone/common/sql/migration_helpers.py
@@ -21,37 +21,25 @@ import migrate
from migrate import exceptions
from oslo_config import cfg
from oslo_db.sqlalchemy import migration
-from oslo_serialization import jsonutils
from oslo_utils import importutils
import six
import sqlalchemy
from keystone.common import sql
-from keystone.common.sql import migrate_repo
from keystone import contrib
from keystone import exception
from keystone.i18n import _
CONF = cfg.CONF
-DEFAULT_EXTENSIONS = ['endpoint_filter',
- 'endpoint_policy',
- 'federation',
- 'oauth1',
- 'revoke',
- ]
-
-
-def get_default_domain():
- # Return the reference used for the default domain structure during
- # sql migrations.
- return {
- 'id': CONF.identity.default_domain_id,
- 'name': 'Default',
- 'enabled': True,
- 'extra': jsonutils.dumps({'description': 'Owns users and tenants '
- '(i.e. projects) available '
- 'on Identity API v2.'})}
+DEFAULT_EXTENSIONS = []
+
+MIGRATED_EXTENSIONS = ['endpoint_policy',
+ 'federation',
+ 'oauth1',
+ 'revoke',
+ 'endpoint_filter'
+ ]
# Different RDBMSs use different schemes for naming the Foreign Key
@@ -117,9 +105,8 @@ def rename_tables_with_constraints(renames, constraints, engine):
`renames` is a dict, mapping {'to_table_name': from_table, ...}
"""
-
if engine.name != 'sqlite':
- # Sqlite doesn't support constraints, so nothing to remove.
+ # SQLite doesn't support constraints, so nothing to remove.
remove_constraints(constraints)
for to_table_name in renames:
@@ -141,11 +128,34 @@ def find_migrate_repo(package=None, repo_name='migrate_repo'):
def _sync_common_repo(version):
abs_path = find_migrate_repo()
- init_version = migrate_repo.DB_INIT_VERSION
- engine = sql.get_engine()
- _assert_not_schema_downgrade(version=version)
- migration.db_sync(engine, abs_path, version=version,
- init_version=init_version, sanity_check=False)
+ init_version = get_init_version()
+ with sql.session_for_write() as session:
+ engine = session.get_bind()
+ _assert_not_schema_downgrade(version=version)
+ migration.db_sync(engine, abs_path, version=version,
+ init_version=init_version, sanity_check=False)
+
+
+def get_init_version(abs_path=None):
+ """Get the initial version of a migrate repository
+
+ :param abs_path: Absolute path to migrate repository.
+ :return: initial version number or None, if DB is empty.
+ """
+ if abs_path is None:
+ abs_path = find_migrate_repo()
+
+ repo = migrate.versioning.repository.Repository(abs_path)
+
+ # Sadly, Repository has a `latest` but not an `oldest`.
+ # The value is a VerNum object which needs to be converted into an int.
+ oldest = int(min(repo.versions.versions))
+
+ if oldest < 1:
+ return None
+
+ # The initial version is one less
+ return oldest - 1
def _assert_not_schema_downgrade(extension=None, version=None):
@@ -153,40 +163,46 @@ def _assert_not_schema_downgrade(extension=None, version=None):
try:
current_ver = int(six.text_type(get_db_version(extension)))
if int(version) < current_ver:
- raise migration.exception.DbMigrationError()
- except exceptions.DatabaseNotControlledError:
+ raise migration.exception.DbMigrationError(
+ _("Unable to downgrade schema"))
+ except exceptions.DatabaseNotControlledError: # nosec
# NOTE(morganfainberg): The database is not controlled, this action
# cannot be a downgrade.
pass
def _sync_extension_repo(extension, version):
- init_version = 0
- engine = sql.get_engine()
+ if extension in MIGRATED_EXTENSIONS:
+ raise exception.MigrationMovedFailure(extension=extension)
+
+ with sql.session_for_write() as session:
+ engine = session.get_bind()
- try:
- package_name = '.'.join((contrib.__name__, extension))
- package = importutils.import_module(package_name)
- except ImportError:
- raise ImportError(_("%s extension does not exist.")
- % package_name)
- try:
- abs_path = find_migrate_repo(package)
try:
- migration.db_version_control(sql.get_engine(), abs_path)
- # Register the repo with the version control API
- # If it already knows about the repo, it will throw
- # an exception that we can safely ignore
- except exceptions.DatabaseAlreadyControlledError:
- pass
- except exception.MigrationNotProvided as e:
- print(e)
- sys.exit(1)
+ package_name = '.'.join((contrib.__name__, extension))
+ package = importutils.import_module(package_name)
+ except ImportError:
+ raise ImportError(_("%s extension does not exist.")
+ % package_name)
+ try:
+ abs_path = find_migrate_repo(package)
+ try:
+ migration.db_version_control(engine, abs_path)
+ # Register the repo with the version control API
+ # If it already knows about the repo, it will throw
+ # an exception that we can safely ignore
+ except exceptions.DatabaseAlreadyControlledError: # nosec
+ pass
+ except exception.MigrationNotProvided as e:
+ print(e)
+ sys.exit(1)
+
+ _assert_not_schema_downgrade(extension=extension, version=version)
- _assert_not_schema_downgrade(extension=extension, version=version)
+ init_version = get_init_version(abs_path=abs_path)
- migration.db_sync(engine, abs_path, version=version,
- init_version=init_version, sanity_check=False)
+ migration.db_sync(engine, abs_path, version=version,
+ init_version=init_version, sanity_check=False)
def sync_database_to_version(extension=None, version=None):
@@ -203,8 +219,10 @@ def sync_database_to_version(extension=None, version=None):
def get_db_version(extension=None):
if not extension:
- return migration.db_version(sql.get_engine(), find_migrate_repo(),
- migrate_repo.DB_INIT_VERSION)
+ with sql.session_for_write() as session:
+ return migration.db_version(session.get_bind(),
+ find_migrate_repo(),
+ get_init_version())
try:
package_name = '.'.join((contrib.__name__, extension))
@@ -213,8 +231,9 @@ def get_db_version(extension=None):
raise ImportError(_("%s extension does not exist.")
% package_name)
- return migration.db_version(
- sql.get_engine(), find_migrate_repo(package), 0)
+ with sql.session_for_write() as session:
+ return migration.db_version(
+ session.get_bind(), find_migrate_repo(package), 0)
def print_db_version(extension=None):