Drop project.id foreign keys

In 2bd88d30 we added a new column domain_id to the user table to
deduplicate the domain_id columns in the local_user and nonlocal_user
tables, and at that point made the user.domain_id column a foreign key
referencing the project.id column. This is a problem that led to
3d46c8a5 in which we removed the ability for the resource driver to be
pluggable, since we had linked two sql backends together and made them
reliant on one another.

This commit removes the foreign key constraint from the user table and
the identity_provider table. For the user table, the sqlalchemy model
never reflected this schema so we don't need to change the model. For
the identity_provider table, we need to update the model. In both cases,
we already enforce, at the manager layer, the constraint that the
domain_id needs to reference a real domain ID[1][2], so we do not need
to rely on this constraint at the database layer.

[1] 43142e4470/keystone/identity/core.py (L935)
[2] 43142e4470/keystone/federation/core.py (L73-L77)

Partial-bug: #1672713

Change-Id: I7c068e350811e22622d1f1e7d8b0a55d4d7cab11
This commit is contained in:
Colleen Murphy 2019-10-09 16:30:33 -07:00
parent e4626f4bc3
commit c4d6097788
6 changed files with 112 additions and 2 deletions

View File

@ -0,0 +1,47 @@
# Copyright 2019 SUSE LLC
#
# 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 Train backports. Do not use this number for new
# Ussuri work. New Ussuri work starts after all the placeholders.
import migrate
import sqlalchemy as sql
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
user = sql.Table('user', meta, autoload=True)
project = sql.Table('project', meta, autoload=True)
fk_name = [
c for c in user.constraints
if isinstance(c, sql.ForeignKeyConstraint)
and c.column_keys == ['domain_id']
][0].name
fk_constraint = migrate.ForeignKeyConstraint(
columns=[user.c.domain_id], refcolumns=[project.c.id])
fk_constraint.name = fk_name
fk_constraint.drop()
identity_provider = sql.Table('identity_provider', meta, autoload=True)
fk_name = [
c for c in identity_provider.constraints
if isinstance(c, sql.ForeignKeyConstraint)
and c.column_keys == ['domain_id']
][0].name
fk_constraint = migrate.ForeignKeyConstraint(
columns=[identity_provider.c.domain_id], refcolumns=[project.c.id])
fk_constraint.name = fk_name
fk_constraint.drop()

View File

@ -0,0 +1,20 @@
# Copyright 2019 SUSE LLC
#
# 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 Train backports. Do not use this number for new
# Ussuri work. New Ussuri work starts after all the placeholders.
def upgrade(migrate_engine):
pass

View File

@ -0,0 +1,20 @@
# Copyright 2019 SUSE LLC
#
# 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 Train backports. Do not use this number for new
# Ussuri work. New Ussuri work starts after all the placeholders.
def upgrade(migrate_engine):
pass

View File

@ -56,8 +56,7 @@ class IdentityProviderModel(sql.ModelBase, sql.ModelDictMixin):
mutable_attributes = frozenset(['description', 'enabled', 'remote_ids'])
id = sql.Column(sql.String(64), primary_key=True)
domain_id = sql.Column(sql.String(64), sql.ForeignKey('project.id'),
nullable=False)
domain_id = sql.Column(sql.String(64), nullable=False)
enabled = sql.Column(sql.Boolean, nullable=False)
description = sql.Column(sql.Text(), nullable=True)
remote_ids = orm.relationship('IdPRemoteIdsModel',

View File

@ -3458,6 +3458,21 @@ class FullMigration(SqlMigrateBase, unit.TestCase):
role_option,
['role_id', 'option_id', 'option_value'])
def test_migration_072_drop_domain_id_fk(self):
self.expand(71)
self.migrate(71)
self.contract(71)
self.assertTrue(self.does_fk_exist('user', 'domain_id'))
self.assertTrue(self.does_fk_exist('identity_provider', 'domain_id'))
self.expand(72)
self.migrate(72)
self.contract(72)
self.assertFalse(self.does_fk_exist('user', 'domain_id'))
self.assertFalse(self.does_fk_exist('identity_provider', 'domain_id'))
class MySQLOpportunisticFullMigration(FullMigration):
FIXTURE = db_fixtures.MySQLOpportunisticFixture

View File

@ -0,0 +1,9 @@
---
upgrade:
- |
The foreign key constraint between the ``user.domain_id`` column and the
``project.id`` column and between the ``identity_provider.domain_id``
column and the ``project.id`` column will be dropped upon running the
keystone db_sync contraction step. These constraints are enforced in code
and do not need to be enforced by the database. This should have no impact
on users.