Move redelegation fields out of extras

The trust SQL backend uses the extras column to store the
redeletegated_trust_id and redelegation_count info. It's
better to make them first class citizens and give them
their own columns.

This change does not add redelegation_trust_id to the trust schema
because this value is set by the token context, not by the user. We also
remove it from the api-ref example to avoid confusion about this.

Co-Authored-By: David Stanek <dstanek@dstanek.com>
Co-Authored-By: Alexander Makarov <amakarov@mirantis.com>
Change-Id: If496152e40d2213a03faad5645667220fddfcf62
This commit is contained in:
Jorge Munoz 2016-02-04 22:23:42 +00:00 committed by Colleen Murphy
parent 91daa40e1f
commit 2b9d409f0d
6 changed files with 173 additions and 2 deletions

View File

@ -116,7 +116,6 @@ Parameters
- allow_redelegation: allow_redelegation
- expires_at: trust_expires_at
- project_id: trust_project_id
- redelegated_trust_id: redelegated_trust_id
- redelegation_count: redelegation_count
- remaining_uses: remaining_uses
- roles: trust_roles

View File

@ -0,0 +1,15 @@
# 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.
def upgrade(migrate_engine):
pass

View File

@ -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.
from oslo_serialization import jsonutils
import sqlalchemy as sql
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
trust_table = sql.Table('trust', meta, autoload=True)
trust_list = list(trust_table.select().execute())
# Loop through all the trusts and move the redelegeated trust id out of
# extras.
for trust in trust_list:
if trust.extra is not None:
extra_dict = jsonutils.loads(trust.extra)
else:
extra_dict = {}
new_values = {}
new_values['redelegated_trust_id'] = extra_dict.pop(
'redelegated_trust_id', None)
new_values['redelegation_count'] = extra_dict.pop(
'redelegation_count', None)
new_values['extra'] = jsonutils.dumps(extra_dict)
clause = trust_table.c.id == trust.id
update = trust_table.update().where(clause).values(new_values)
migrate_engine.execute(update)

View File

@ -0,0 +1,31 @@
# 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
trust_table = sql.Table('trust', meta, autoload=True)
trust_id_column = sql.Column(
'redelegated_trust_id',
sql.String(64),
nullable=True)
count_column = sql.Column(
'redelegation_count',
sql.Integer,
nullable=True)
trust_table.create_column(trust_id_column)
trust_table.create_column(count_column)

View File

@ -52,6 +52,7 @@ from oslo_db import exception as db_exception
from oslo_db.sqlalchemy import enginefacade
from oslo_db.sqlalchemy import test_fixtures as db_fixtures
from oslo_log import log
from oslo_serialization import jsonutils
from oslotest import base as test_base
import pytz
from sqlalchemy.engine import reflection
@ -3283,6 +3284,85 @@ class FullMigration(SqlMigrateBase, unit.TestCase):
app_cred_access_rule_table.insert().values(
app_cred_access_rule_rel).execute()
def test_migration_062_add_trust_redelegation(self):
# ensure initial schema
self.expand(61)
self.migrate(61)
self.contract(61)
self.assertTableColumns('trust', ['id',
'trustor_user_id',
'trustee_user_id',
'project_id',
'impersonation',
'expires_at',
'expires_at_int',
'remaining_uses',
'deleted_at',
'extra'])
# fixture
trust = {
'id': uuid.uuid4().hex,
'trustor_user_id': uuid.uuid4().hex,
'trustee_user_id': uuid.uuid4().hex,
'project_id': uuid.uuid4().hex,
'impersonation': True,
'expires_at': datetime.datetime.now(),
'remaining_uses': 10,
'deleted_at': datetime.datetime.now(),
'redelegated_trust_id': uuid.uuid4().hex,
'redelegation_count': 3,
'other': uuid.uuid4().hex
}
old_trust = trust.copy()
old_extra = {
'redelegated_trust_id': old_trust.pop('redelegated_trust_id'),
'redelegation_count': old_trust.pop('redelegation_count'),
'other': old_trust.pop('other')
}
old_trust['extra'] = jsonutils.dumps(old_extra)
# load fixture
session = self.sessionmaker()
self.insert_dict(session, 'trust', old_trust)
# ensure redelegation data is in extra
stored_trust = list(self.select_table('trust').execute())[0]
self.assertDictEqual({
'redelegated_trust_id': trust['redelegated_trust_id'],
'redelegation_count': trust['redelegation_count'],
'other': trust['other']},
jsonutils.loads(stored_trust.extra))
# upgrade and ensure expected schema
self.expand(62)
self.migrate(62)
self.contract(62)
self.assertTableColumns('trust', ['id',
'trustor_user_id',
'trustee_user_id',
'project_id',
'impersonation',
'expires_at',
'expires_at_int',
'remaining_uses',
'deleted_at',
'redelegated_trust_id',
'redelegation_count',
'extra'])
trust_table = sqlalchemy.Table('trust', self.metadata, autoload=True)
self.assertTrue(trust_table.c.redelegated_trust_id.nullable)
self.assertTrue(trust_table.c.redelegation_count.nullable)
# test target data layout
upgraded_trust = list(self.select_table('trust').execute())[0]
self.assertDictEqual({'other': trust['other']},
jsonutils.loads(upgraded_trust.extra))
self.assertEqual(trust['redelegated_trust_id'],
upgraded_trust.redelegated_trust_id)
self.assertEqual(trust['redelegation_count'],
upgraded_trust.redelegation_count)
class MySQLOpportunisticFullMigration(FullMigration):
FIXTURE = db_fixtures.MySQLOpportunisticFixture

View File

@ -32,7 +32,8 @@ class TrustModel(sql.ModelBase, sql.ModelDictMixinWithExtras):
__tablename__ = 'trust'
attributes = ['id', 'trustor_user_id', 'trustee_user_id',
'project_id', 'impersonation', 'expires_at',
'remaining_uses', 'deleted_at']
'remaining_uses', 'deleted_at', 'redelegated_trust_id',
'redelegation_count']
id = sql.Column(sql.String(64), primary_key=True)
# user id of owner
trustor_user_id = sql.Column(sql.String(64), nullable=False,)
@ -44,6 +45,8 @@ class TrustModel(sql.ModelBase, sql.ModelDictMixinWithExtras):
_expires_at = sql.Column('expires_at', sql.DateTime)
expires_at_int = sql.Column(sql.DateTimeInt(), nullable=True)
remaining_uses = sql.Column(sql.Integer, nullable=True)
redelegated_trust_id = sql.Column(sql.String(64), nullable=True)
redelegation_count = sql.Column(sql.Integer, nullable=True)
extra = sql.Column(sql.JsonBlob())
__table_args__ = (sql.UniqueConstraint(
'trustor_user_id', 'trustee_user_id', 'project_id',