Merge "Collapse SQL Migrations"

This commit is contained in:
Jenkins
2014-04-14 16:59:44 +00:00
committed by Gerrit Code Review
42 changed files with 456 additions and 4756 deletions
@@ -1,155 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
def upgrade(migrate_engine):
# Upgrade operations go here. Don't create your own engine; bind
# migrate_engine to your metadata
meta = sql.MetaData()
meta.bind = migrate_engine
# catalog
service_table = sql.Table(
'service',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('type', sql.String(255)),
sql.Column('extra', sql.Text()))
service_table.create(migrate_engine, checkfirst=True)
endpoint_table = sql.Table(
'endpoint',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('region', sql.String(255)),
sql.Column('service_id',
sql.String(64),
sql.ForeignKey('service.id'),
nullable=False),
sql.Column('extra', sql.Text()))
endpoint_table.create(migrate_engine, checkfirst=True)
# identity
role_table = sql.Table(
'role',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(255), unique=True, nullable=False))
role_table.create(migrate_engine, checkfirst=True)
if migrate_engine.name == 'ibm_db_sa':
# NOTE(blk-u): SQLAlchemy for PostgreSQL picks the name tenant_name_key
# for the unique constraint, but for DB2 doesn't give the UC a name
# unless we tell it to and there is no DDL to alter a column to drop
# an unnamed unique constraint, so this code creates a named unique
# constraint on the name column rather than an unnamed one.
# (This is used in migration 16.)
tenant_table = sql.Table(
'tenant',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), nullable=False),
sql.Column('extra', sql.Text()),
sql.UniqueConstraint('name', name='tenant_name_key'))
else:
tenant_table = sql.Table(
'tenant',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), unique=True, nullable=False),
sql.Column('extra', sql.Text()))
tenant_table.create(migrate_engine, checkfirst=True)
metadata_table = sql.Table(
'metadata',
meta,
sql.Column('user_id', sql.String(64), primary_key=True),
sql.Column('tenant_id', sql.String(64), primary_key=True),
sql.Column('data', sql.Text()))
metadata_table.create(migrate_engine, checkfirst=True)
ec2_credential_table = sql.Table(
'ec2_credential',
meta,
sql.Column('access', sql.String(64), primary_key=True),
sql.Column('secret', sql.String(64)),
sql.Column('user_id', sql.String(64)),
sql.Column('tenant_id', sql.String(64)))
ec2_credential_table.create(migrate_engine, checkfirst=True)
if migrate_engine.name == 'ibm_db_sa':
# NOTE(blk-u): SQLAlchemy for PostgreSQL picks the name user_name_key
# for the unique constraint, but for DB2 doesn't give the UC a name
# unless we tell it to and there is no DDL to alter a column to drop
# an unnamed unique constraint, so this code creates a named unique
# constraint on the name column rather than an unnamed one.
# (This is used in migration 16.)
user_table = sql.Table(
'user',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), nullable=False),
sql.Column('extra', sql.Text()),
sql.UniqueConstraint('name', name='user_name_key'))
else:
user_table = sql.Table(
'user',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), unique=True, nullable=False),
sql.Column('extra', sql.Text()))
user_table.create(migrate_engine, checkfirst=True)
user_tenant_membership_table = sql.Table(
'user_tenant_membership',
meta,
sql.Column(
'user_id',
sql.String(64),
sql.ForeignKey('user.id'),
primary_key=True),
sql.Column(
'tenant_id',
sql.String(64),
sql.ForeignKey('tenant.id'),
primary_key=True))
user_tenant_membership_table.create(migrate_engine, checkfirst=True)
# token
token_table = sql.Table(
'token',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('expires', sql.DateTime()),
sql.Column('extra', sql.Text()))
token_table.create(migrate_engine, checkfirst=True)
def downgrade(migrate_engine):
# Operations to reverse the above upgrade go here.
meta = sql.MetaData()
meta.bind = migrate_engine
tables = ['user_tenant_membership', 'token', 'user', 'tenant', 'role',
'metadata', 'ec2_credential', 'endpoint', 'service']
for t in tables:
table = sql.Table(t, meta, autoload=True)
table.drop(migrate_engine, checkfirst=True)
@@ -1,8 +0,0 @@
drop table token;
CREATE TABLE token (
id VARCHAR(64) NOT NULL,
expires DATETIME,
extra TEXT,
PRIMARY KEY (id)
);
@@ -1,27 +0,0 @@
CREATE TABLE token_backup (
id_hash VARCHAR(64) NOT NULL,
id VARCHAR(1024),
expires DATETIME,
extra TEXT,
PRIMARY KEY (id_hash)
);
insert into token_backup
select id as old_id,
'',
expires as old_expires,
extra as old_extra from token;
drop table token;
CREATE TABLE token (
id_hash VARCHAR(64) NOT NULL,
id VARCHAR(1024),
expires DATETIME,
extra TEXT,
PRIMARY KEY (id_hash)
);
insert into token select * from token_backup;
drop table token_backup;
@@ -1,41 +0,0 @@
# Copyright (c) 2012 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from sqlalchemy import Column, MetaData, String, Table
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
token = Table('token', meta, autoload=True)
old_id_col = token.c.id
old_id_col.alter(name='id_hash')
# Note: We obtain a new metadata reference to avoid
# sqlalchemy.exc.ArgumentError:
# Trying to redefine primary-key column 'id' as a non-primary-key...
meta = MetaData()
meta.bind = migrate_engine
token = Table('token', meta, autoload=True)
new_id = Column("id", String(2048))
token.create_column(new_id)
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
token = Table('token', meta, autoload=True)
token.drop_column('id')
token = Table('token', meta, autoload=True)
id_col = token.c.id_hash
id_col.alter(name='id')
@@ -1,3 +0,0 @@
alter TABLE token ADD valid integer;
update token set valid = 1;
@@ -1,36 +0,0 @@
# Copyright 2012 OpenStack 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.
import sqlalchemy as sql
def upgrade(migrate_engine):
# Upgrade operations go here. Don't create your own engine; bind
meta = sql.MetaData()
meta.bind = migrate_engine
token = sql.Table('token', meta, autoload=True)
# creating the column immediately with nullable=False fails with
# PostgreSQL (LP 1068181), so do it in two steps instead
valid = sql.Column(
'valid', sql.Boolean(), sql.ColumnDefault(True), nullable=True)
valid.create(token, populate_default=True)
valid.alter(type=sql.Boolean(), default=True, nullable=False)
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
token = sql.Table('token', meta, autoload=True)
token.drop_column('valid')
@@ -1,41 +0,0 @@
# Copyright (c) 2012 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from sqlalchemy import Column, MetaData, String, Table
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
token = Table('token', meta, autoload=True)
old_id_col = token.c.id
old_id_col.alter(name='id_hash')
# Note: We obtain a new metadata reference to avoid
# sqlalchemy.exc.ArgumentError:
# Trying to redefine primary-key column 'id' as a non-primary-key...
meta = MetaData()
meta.bind = migrate_engine
token = Table('token', meta, autoload=True)
new_id = Column("id", String(2048))
token.create_column(new_id)
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
token = Table('token', meta, autoload=True)
token.drop_column('id')
token = Table('token', meta, autoload=True)
id_col = token.c.id_hash
id_col.alter(name='id')
@@ -1,48 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from sqlalchemy import MetaData
def upgrade(migrate_engine):
# Upgrade operations go here. Don't create your own engine; bind
# migrate_engine to your metadata
meta = MetaData()
meta.bind = migrate_engine
if migrate_engine.name == "mysql":
tables = ['tenant', 'user', 'role', 'token', 'service', 'metadata',
'ec2_credential', 'endpoint', 'user_tenant_membership']
sql = "SET foreign_key_checks = 0;"
for table in tables:
sql += "ALTER TABLE %s CONVERT TO CHARACTER SET utf8;" % table
sql += "SET foreign_key_checks = 1;"
sql += "ALTER DATABASE %s DEFAULT CHARACTER SET utf8;" \
% migrate_engine.url.database
migrate_engine.execute(sql)
def downgrade(migrate_engine):
# Operations to reverse the above upgrade go here.
if migrate_engine.name == "mysql":
tables = ['tenant', 'user', 'role', 'token', 'service', 'metadata',
'ec2_credential', 'endpoint', 'user_tenant_membership']
sql = "SET foreign_key_checks = 0;"
for table in tables:
sql += "ALTER TABLE %s CONVERT TO CHARACTER SET latin1;" % table
sql += "SET foreign_key_checks = 1;"
sql += "ALTER DATABASE %s DEFAULT CHARACTER SET latin1;" \
% migrate_engine.url.database
@@ -1,37 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
policy_table = sql.Table(
'policy',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('type', sql.String(255), nullable=False),
sql.Column('blob', sql.Text(), nullable=False),
sql.Column('extra', sql.Text()))
policy_table.create(migrate_engine, checkfirst=True)
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
policy_table = sql.Table('policy', meta, autoload=True)
policy_table.drop(migrate_engine, checkfirst=True)
@@ -1,82 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
def upgrade(migrate_engine):
# Upgrade operations go here. Don't create your own engine; bind
# migrate_engine to your metadata
meta = sql.MetaData()
meta.bind = migrate_engine
domain_table = sql.Table(
'domain',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), unique=True, nullable=False),
sql.Column('enabled', sql.Boolean, nullable=False, default=True),
sql.Column('extra', sql.Text()))
domain_table.create(migrate_engine, checkfirst=True)
sql.Table('user', meta, autoload=True)
user_domain_metadata_table = sql.Table(
'user_domain_metadata',
meta,
sql.Column(
'user_id',
sql.String(64),
sql.ForeignKey('user.id'),
primary_key=True),
sql.Column(
'domain_id',
sql.String(64),
sql.ForeignKey('domain.id'),
primary_key=True),
sql.Column('data', sql.Text()))
user_domain_metadata_table.create(migrate_engine, checkfirst=True)
sql.Table('tenant', meta, autoload=True)
credential_table = sql.Table(
'credential',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('user_id',
sql.String(64),
sql.ForeignKey('user.id'),
nullable=False),
sql.Column('project_id',
sql.String(64),
sql.ForeignKey('tenant.id')),
sql.Column('blob', sql.Text(), nullable=False),
sql.Column('type', sql.String(255), nullable=False),
sql.Column('extra', sql.Text()))
credential_table.create(migrate_engine, checkfirst=True)
role = sql.Table('role', meta, autoload=True)
extra = sql.Column('extra', sql.Text())
role.create_column(extra)
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
role = sql.Table('role', meta, autoload=True)
role.drop_column('extra')
tables = ['user_domain_metadata', 'credential', 'domain']
for t in tables:
table = sql.Table(t, meta, autoload=True)
table.drop(migrate_engine, checkfirst=True)
@@ -1,57 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import sqlalchemy as sql
from sqlalchemy import orm
from keystone import config
CONF = config.CONF
def upgrade(migrate_engine):
"""Creates the default domain."""
meta = sql.MetaData()
meta.bind = migrate_engine
domain_table = sql.Table('domain', meta, autoload=True)
domain = {
'id': CONF.identity.default_domain_id,
'name': 'Default',
'enabled': True,
'extra': json.dumps({
'description': 'Owns users and tenants (i.e. projects) available '
'on Identity API v2.'})}
session = orm.sessionmaker(bind=migrate_engine)()
insert = domain_table.insert()
insert.execute(domain)
session.commit()
def downgrade(migrate_engine):
"""Delete the default domain."""
meta = sql.MetaData()
meta.bind = migrate_engine
sql.Table('domain', meta, autoload=True)
session = orm.sessionmaker(bind=migrate_engine)()
session.execute(
'DELETE FROM domain WHERE id=:id',
{'id': CONF.identity.default_domain_id})
session.commit()
@@ -1,110 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from sqlalchemy import Column, MetaData, String, Table, Text, types
from sqlalchemy.orm import sessionmaker
# sqlite doesn't support dropping columns. Copy to a new table instead
def downgrade_user_table_with_copy(meta, migrate_engine):
maker = sessionmaker(bind=migrate_engine)
session = maker()
session.execute("ALTER TABLE user RENAME TO orig_user;")
user_table = Table(
'user',
meta,
Column('id', String(64), primary_key=True),
Column('name', String(64), unique=True, nullable=False),
Column('extra', Text()))
user_table.create(migrate_engine, checkfirst=True)
orig_user_table = Table('orig_user', meta, autoload=True)
for user in session.query(orig_user_table):
session.execute("insert into user (id, name, extra) "
"values ( :id, :name, :extra);",
{'id': user.id,
'name': user.name,
'extra': user.extra})
session.execute("drop table orig_user;")
session.close()
def downgrade_tenant_table_with_copy(meta, migrate_engine):
maker = sessionmaker(bind=migrate_engine)
session = maker()
session.execute("ALTER TABLE tenant RENAME TO orig_tenant;")
tenant_table = Table(
'tenant',
meta,
Column('id', String(64), primary_key=True),
Column('name', String(64), unique=True, nullable=False),
Column('extra', Text()))
tenant_table.create(migrate_engine, checkfirst=True)
orig_tenant_table = Table('orig_tenant', meta, autoload=True)
for tenant in session.query(orig_tenant_table):
session.execute("insert into tenant (id, name, extra) "
"values ( :id, :name, :extra);",
{'id': tenant.id,
'name': tenant.name,
'extra': tenant.extra})
session.execute("drop table orig_tenant;")
session.close()
def downgrade_user_table_with_column_drop(meta, migrate_engine):
user_table = Table('user', meta, autoload=True)
user_table.drop_column(Column('password', String(128)))
user_table.drop_column(Column('enabled', types.Boolean,
default=True))
def downgrade_tenant_table_with_column_drop(meta, migrate_engine):
tenant_table = Table('tenant', meta, autoload=True)
tenant_table.drop_column(Column('description', Text()))
tenant_table.drop_column(Column('enabled', types.Boolean))
def upgrade_user_table(meta, migrate_engine):
user_table = Table('user', meta, autoload=True)
user_table.create_column(Column('password', String(128)))
user_table.create_column(Column('enabled', types.Boolean,
default=True))
def upgrade_tenant_table(meta, migrate_engine):
tenant_table = Table('tenant', meta, autoload=True)
tenant_table.create_column(Column('description', Text()))
tenant_table.create_column(Column('enabled', types.Boolean))
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
upgrade_user_table(meta, migrate_engine)
upgrade_tenant_table(meta, migrate_engine)
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
if migrate_engine.name == 'sqlite':
downgrade_user_table_with_copy(meta, migrate_engine)
downgrade_tenant_table_with_copy(meta, migrate_engine)
else:
downgrade_user_table_with_column_drop(meta, migrate_engine)
downgrade_tenant_table_with_column_drop(meta, migrate_engine)
@@ -1,103 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import six
from sqlalchemy import MetaData, Table
from sqlalchemy.orm import sessionmaker
DISABLED_VALUES = ['false', 'disabled', 'no', '0']
def is_enabled(enabled):
# no explicit value means enabled
if enabled is True or enabled is None:
return True
if (isinstance(enabled, six.string_types)
and enabled.lower() in DISABLED_VALUES):
return False
return bool(enabled)
def downgrade_user_table(meta, migrate_engine, session):
user_table = Table('user', meta, autoload=True)
for user in session.query(user_table).all():
extra = json.loads(user.extra)
extra['password'] = user.password
extra['enabled'] = '%r' % is_enabled(user.enabled)
values = {'extra': json.dumps(extra)}
update = user_table.update().\
where(user_table.c.id == user.id).\
values(values)
migrate_engine.execute(update)
def downgrade_tenant_table(meta, migrate_engine, session):
tenant_table = Table('tenant', meta, autoload=True)
for tenant in session.query(tenant_table).all():
extra = json.loads(tenant.extra)
extra['description'] = tenant.description
extra['enabled'] = '%r' % is_enabled(tenant.enabled)
values = {'extra': json.dumps(extra)}
update = tenant_table.update().\
where(tenant_table.c.id == tenant.id).\
values(values)
migrate_engine.execute(update)
def upgrade_user_table(meta, migrate_engine, session):
user_table = Table('user', meta, autoload=True)
for user in session.query(user_table).all():
extra = json.loads(user.extra)
values = {'password': extra.pop('password', None),
'enabled': is_enabled(extra.pop('enabled', True)),
'extra': json.dumps(extra)}
update = user_table.update().\
where(user_table.c.id == user.id).\
values(values)
migrate_engine.execute(update)
def upgrade_tenant_table(meta, migrate_engine, session):
tenant_table = Table('tenant', meta, autoload=True)
for tenant in session.query(tenant_table):
extra = json.loads(tenant.extra)
values = {'description': extra.pop('description', None),
'enabled': is_enabled(extra.pop('enabled', True)),
'extra': json.dumps(extra)}
update = tenant_table.update().\
where(tenant_table.c.id == tenant.id).\
values(values)
migrate_engine.execute(update)
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
session = sessionmaker(bind=migrate_engine)()
upgrade_user_table(meta, migrate_engine, session)
upgrade_tenant_table(meta, migrate_engine, session)
session.commit()
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
session = sessionmaker(bind=migrate_engine)()
downgrade_user_table(meta, migrate_engine, session)
downgrade_tenant_table(meta, migrate_engine, session)
session.commit()
@@ -1,68 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
from keystone.common.sql import migration_helpers
def upgrade(migrate_engine):
"""Create API-version specific endpoint tables."""
meta = sql.MetaData()
meta.bind = migrate_engine
legacy_table = sql.Table('endpoint', meta, autoload=True)
renames = {'endpoint_v2': legacy_table}
service_table = sql.Table('service', meta, autoload=True)
constraints = [{'table': legacy_table,
'fk_column': 'service_id',
'ref_column': service_table.c.id}]
migration_helpers.rename_tables_with_constraints(renames, constraints,
migrate_engine)
sql.Table('service', meta, autoload=True)
new_table = sql.Table(
'endpoint_v3',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('legacy_endpoint_id', sql.String(64)),
sql.Column('interface', sql.String(8), nullable=False),
sql.Column('region', sql.String(255)),
sql.Column('service_id',
sql.String(64),
sql.ForeignKey('service.id'),
nullable=False),
sql.Column('url', sql.Text(), nullable=False),
sql.Column('extra', sql.Text()))
new_table.create(migrate_engine, checkfirst=True)
def downgrade(migrate_engine):
"""Replace API-version specific endpoint tables with one based on v2."""
meta = sql.MetaData()
meta.bind = migrate_engine
new_table = sql.Table('endpoint_v3', meta, autoload=True)
new_table.drop()
legacy_table = sql.Table('endpoint_v2', meta, autoload=True)
renames = {'endpoint': legacy_table}
service_table = sql.Table('service', meta, autoload=True)
constraints = [{'table': legacy_table,
'fk_column': 'service_id',
'ref_column': service_table.c.id}]
migration_helpers.rename_tables_with_constraints(renames, constraints,
migrate_engine)
@@ -1,97 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import uuid
import sqlalchemy as sql
from sqlalchemy import orm
ENDPOINT_TYPES = ['public', 'internal', 'admin']
def upgrade(migrate_engine):
"""Split each legacy endpoint into separate records for each interface."""
meta = sql.MetaData()
meta.bind = migrate_engine
legacy_table = sql.Table('endpoint_v2', meta, autoload=True)
new_table = sql.Table('endpoint_v3', meta, autoload=True)
session = orm.sessionmaker(bind=migrate_engine)()
for ref in session.query(legacy_table).all():
# pull urls out of extra
extra = json.loads(ref.extra)
urls = dict((i, extra.pop('%surl' % i)) for i in ENDPOINT_TYPES)
for interface in ENDPOINT_TYPES:
endpoint = {
'id': uuid.uuid4().hex,
'legacy_endpoint_id': ref.id,
'interface': interface,
'region': ref.region,
'service_id': ref.service_id,
'url': urls[interface],
'extra': json.dumps(extra),
}
insert = new_table.insert().values(endpoint)
migrate_engine.execute(insert)
session.commit()
session.close()
def downgrade(migrate_engine):
"""Re-create the v2 endpoints table based on v3 endpoints."""
meta = sql.MetaData()
meta.bind = migrate_engine
legacy_table = sql.Table('endpoint_v2', meta, autoload=True)
new_table = sql.Table('endpoint_v3', meta, autoload=True)
session = orm.sessionmaker(bind=migrate_engine)()
for ref in session.query(new_table).all():
extra = json.loads(ref.extra)
legacy_id = ref.legacy_endpoint_id or extra.get('legacy_endpoint_id')
if not legacy_id:
continue
q = session.query(legacy_table)
q = q.filter_by(id=legacy_id)
legacy_ref = q.first()
if legacy_ref:
# We already have one, so just update the extra
# attribute with the urls.
extra = json.loads(legacy_ref.extra)
extra['%surl' % ref.interface] = ref.url
values = {'extra': json.dumps(extra)}
update = legacy_table.update().\
where(legacy_table.c.id == legacy_ref.id).\
values(values)
migrate_engine.execute(update)
else:
# This is the first one of this legacy ID, so
# we can insert instead.
extra = json.loads(ref.extra)
extra['%surl' % ref.interface] = ref.url
endpoint = {
'id': legacy_id,
'region': ref.region,
'service_id': ref.service_id,
'extra': json.dumps(extra),
}
insert = legacy_table.insert().values(endpoint)
migrate_engine.execute(insert)
session.commit()
session.close()
@@ -1,65 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
from keystone.common.sql import migration_helpers
def upgrade(migrate_engine):
"""Replace API-version specific endpoint tables with one based on v3."""
meta = sql.MetaData()
meta.bind = migrate_engine
legacy_table = sql.Table('endpoint_v2', meta, autoload=True)
legacy_table.drop()
new_table = sql.Table('endpoint_v3', meta, autoload=True)
renames = {'endpoint': new_table}
service_table = sql.Table('service', meta, autoload=True)
constraints = [{'table': new_table,
'fk_column': 'service_id',
'ref_column': service_table.c.id}]
migration_helpers.rename_tables_with_constraints(renames, constraints,
migrate_engine)
def downgrade(migrate_engine):
"""Create API-version specific endpoint tables."""
meta = sql.MetaData()
meta.bind = migrate_engine
new_table = sql.Table('endpoint', meta, autoload=True)
renames = {'endpoint_v3': new_table}
service_table = sql.Table('service', meta, autoload=True)
constraints = [{'table': new_table,
'fk_column': 'service_id',
'ref_column': service_table.c.id}]
migration_helpers.rename_tables_with_constraints(renames, constraints,
migrate_engine)
sql.Table('service', meta, autoload=True)
legacy_table = sql.Table(
'endpoint_v2',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('region', sql.String(255)),
sql.Column('service_id',
sql.String(64),
sql.ForeignKey('service.id'),
nullable=False),
sql.Column('extra', sql.Text()))
legacy_table.create(migrate_engine, checkfirst=True)
@@ -1,93 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
sql.Table('domain', meta, autoload=True)
group_table = sql.Table(
'group',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('domain_id', sql.String(64), sql.ForeignKey('domain.id'),
nullable=False),
sql.Column('name', sql.String(64), nullable=False),
sql.Column('description', sql.Text()),
sql.Column('extra', sql.Text()),
sql.UniqueConstraint('domain_id', 'name'))
group_table.create(migrate_engine, checkfirst=True)
sql.Table('user', meta, autoload=True)
user_group_membership_table = sql.Table(
'user_group_membership',
meta,
sql.Column(
'user_id',
sql.String(64),
sql.ForeignKey('user.id'),
primary_key=True),
sql.Column(
'group_id',
sql.String(64),
sql.ForeignKey('group.id'),
primary_key=True))
user_group_membership_table.create(migrate_engine, checkfirst=True)
sql.Table('tenant', meta, autoload=True)
group_project_metadata_table = sql.Table(
'group_project_metadata',
meta,
sql.Column(
'group_id',
sql.String(64),
sql.ForeignKey('group.id'),
primary_key=True),
sql.Column(
'project_id',
sql.String(64),
sql.ForeignKey('tenant.id'),
primary_key=True),
sql.Column('data', sql.Text()))
group_project_metadata_table.create(migrate_engine, checkfirst=True)
group_domain_metadata_table = sql.Table(
'group_domain_metadata',
meta,
sql.Column(
'group_id',
sql.String(64),
sql.ForeignKey('group.id'),
primary_key=True),
sql.Column(
'domain_id',
sql.String(64),
sql.ForeignKey('domain.id'),
primary_key=True),
sql.Column('data', sql.Text()))
group_domain_metadata_table.create(migrate_engine, checkfirst=True)
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
tables = ['user_group_membership', 'group_project_metadata',
'group_domain_metadata', 'group']
for t in tables:
table = sql.Table(t, meta, autoload=True)
table.drop(migrate_engine, checkfirst=True)
@@ -1,194 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
from sqlalchemy.orm import sessionmaker
from keystone.common.sql import migration_helpers
def rename_with_constraints(meta, legacy_project_table_name,
new_project_table_name,
legacy_user_project_membership_table_name,
new_user_project_membership_table_name):
# Not all RDBMSs support renaming a table that has foreign key constraints
# on it, so drop FK constraints before renaming and then replace FKs
# afterwards.
credential_table = sql.Table('credential', meta, autoload=True)
group_project_meta_table = sql.Table('group_project_metadata', meta,
autoload=True)
project_table = sql.Table(legacy_project_table_name, meta, autoload=True)
user_project_membership_table = sql.Table(
legacy_user_project_membership_table_name, meta, autoload=True)
user_table = sql.Table('user', meta, autoload=True)
constraints = [{'table': credential_table,
'fk_column': 'project_id',
'ref_column': project_table.c.id},
{'table': group_project_meta_table,
'fk_column': 'project_id',
'ref_column': project_table.c.id},
{'table': user_project_membership_table,
'fk_column': 'tenant_id',
'ref_column': project_table.c.id},
{'table': user_project_membership_table,
'fk_column': 'user_id',
'ref_column': user_table.c.id}]
renames = {
new_project_table_name: project_table,
new_user_project_membership_table_name: user_project_membership_table}
migration_helpers.rename_tables_with_constraints(renames, constraints,
meta.bind)
def upgrade_with_rename(meta, migrate_engine):
legacy_project_table_name = 'tenant'
new_project_table_name = 'project'
legacy_user_project_membership_table_name = 'user_tenant_membership'
new_user_project_membership_table_name = 'user_project_membership'
rename_with_constraints(meta, legacy_project_table_name,
new_project_table_name,
legacy_user_project_membership_table_name,
new_user_project_membership_table_name)
def downgrade_with_rename(meta, migrate_engine):
legacy_project_table_name = 'project'
new_project_table_name = 'tenant'
legacy_user_project_membership_table_name = 'user_project_membership'
new_user_project_membership_table_name = 'user_tenant_membership'
rename_with_constraints(meta, legacy_project_table_name,
new_project_table_name,
legacy_user_project_membership_table_name,
new_user_project_membership_table_name)
def upgrade_with_copy(meta, migrate_engine):
sql.Table('user', meta, autoload=True)
project_table = sql.Table(
'project',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), unique=True, nullable=False),
sql.Column('extra', sql.Text()),
sql.Column('description', sql.Text(), nullable=True),
sql.Column('enabled', sql.types.Boolean, default=True))
project_table.create(migrate_engine, checkfirst=True)
user_project_membership_table = sql.Table(
'user_project_membership',
meta,
sql.Column(
'user_id',
sql.String(64),
sql.ForeignKey('user.id'),
primary_key=True),
sql.Column(
'tenant_id',
sql.String(64),
sql.ForeignKey('project.id'),
primary_key=True))
user_project_membership_table.create(migrate_engine, checkfirst=True)
session = sessionmaker(bind=migrate_engine)()
tenant_table = sql.Table('tenant', meta, autoload=True)
insert = project_table.insert()
for tenant in session.query(tenant_table):
insert.execute({'id': tenant.id,
'name': tenant.name,
'extra': tenant.extra,
'description': tenant.description,
'enabled': tenant.enabled})
user_tenant_membership_table = sql.Table('user_tenant_membership',
meta,
autoload=True)
insert = user_project_membership_table.insert()
for user_id, tenant_id in session.query(user_tenant_membership_table):
insert.execute({'user_id': user_id, 'tenant_id': tenant_id})
session.commit()
session.close()
user_tenant_membership_table.drop()
tenant_table.drop()
def downgrade_with_copy(meta, migrate_engine):
sql.Table('user', meta, autoload=True)
tenant_table = sql.Table(
'tenant',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), unique=True, nullable=False),
sql.Column('extra', sql.Text()),
sql.Column('description', sql.Text(), nullable=True),
sql.Column('enabled', sql.types.Boolean))
tenant_table.create(migrate_engine, checkfirst=True)
user_tenant_membership_table = sql.Table(
'user_tenant_membership',
meta,
sql.Column(
'user_id',
sql.String(64),
sql.ForeignKey('user.id'),
primary_key=True),
sql.Column(
'tenant_id',
sql.String(64),
sql.ForeignKey('tenant.id'),
primary_key=True))
user_tenant_membership_table.create(migrate_engine, checkfirst=True)
session = sessionmaker(bind=migrate_engine)()
project_table = sql.Table('project', meta, autoload=True)
insert = tenant_table.insert()
for project in session.query(project_table):
insert.values(project).execute()
project_table.drop()
user_project_membership_table = sql.Table('user_project_membership',
meta,
autoload=True)
insert = user_tenant_membership_table.insert()
for membership in session.query(user_project_membership_table):
insert.execute(membership)
user_project_membership_table.drop()
session.commit()
session.close()
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
if migrate_engine.name == "sqlite":
upgrade_with_copy(meta, migrate_engine)
else:
upgrade_with_rename(meta, migrate_engine)
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
if migrate_engine.name == "sqlite":
downgrade_with_copy(meta, migrate_engine)
else:
downgrade_with_rename(meta, migrate_engine)
@@ -1,435 +0,0 @@
# Copyright 2012 OpenStack Foundation
# Copyright 2013 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.
"""
Normalize for domain_id, i.e. ensure User and Project entities have the
domain_id as a first class attribute.
Both User and Project (as well as Group) entities are owned by a
domain, which is implemented as each having a domain_id foreign key
in their sql representation that points back to the respective
domain in the domain table. This domain_id attribute should also
be required (i.e. not nullable)
Adding a non_nullable foreign key attribute to a table with existing
data causes a few problems since not all DB engines support the
ability to either control the triggering of integrity constraints
or the ability to modify columns after they are created.
To get round the above inconsistencies, two versions of the
upgrade/downgrade functions are supplied, one for those engines
that support dropping columns, and one for those that don't. For
the latter we are forced to do table copy AND control the triggering
of integrity constraints.
"""
import sqlalchemy as sql
from sqlalchemy.orm import sessionmaker
from keystone import config
CONF = config.CONF
def _disable_foreign_constraints(session, migrate_engine):
if migrate_engine.name == 'mysql':
session.execute('SET foreign_key_checks = 0;')
def _enable_foreign_constraints(session, migrate_engine):
if migrate_engine.name == 'mysql':
session.execute('SET foreign_key_checks = 1;')
def upgrade_user_table_with_copy(meta, migrate_engine, session):
# We want to add the domain_id attribute to the user table. Since
# it is non nullable and the table may have data, easiest way is
# a table copy. Further, in order to keep foreign key constraints
# pointing at the right table, we need to be able and do a table
# DROP then CREATE, rather than ALTERing the name of the table.
# First make a copy of the user table
temp_user_table = sql.Table(
'temp_user',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), unique=True, nullable=False),
sql.Column('extra', sql.Text()),
sql.Column('password', sql.String(128)),
sql.Column('enabled', sql.Boolean, default=True))
temp_user_table.create(migrate_engine, checkfirst=True)
user_table = sql.Table('user', meta, autoload=True)
for user in session.query(user_table):
session.execute('insert into temp_user (id, name, extra, '
'password, enabled) '
'values ( :id, :name, :extra, '
':password, :enabled);',
{'id': user.id,
'name': user.name,
'extra': user.extra,
'password': user.password,
'enabled': user.enabled})
# Now switch off constraints while we drop and then re-create the
# user table, with the additional domain_id column
_disable_foreign_constraints(session, migrate_engine)
session.execute('drop table user;')
# Need to create a new metadata stream since we are going to load a
# different version of the user table
meta2 = sql.MetaData()
meta2.bind = migrate_engine
sql.Table('domain', meta2, autoload=True)
user_table = sql.Table(
'user',
meta2,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), nullable=False),
sql.Column('extra', sql.Text()),
sql.Column("password", sql.String(128)),
sql.Column("enabled", sql.Boolean, default=True),
sql.Column('domain_id', sql.String(64), sql.ForeignKey('domain.id'),
nullable=False),
sql.UniqueConstraint('domain_id', 'name'))
user_table.create(migrate_engine, checkfirst=True)
# Finally copy in the data from our temp table and then clean
# up by deleting our temp table
for user in session.query(temp_user_table):
session.execute('insert into user (id, name, extra, '
'password, enabled, domain_id) '
'values ( :id, :name, :extra, '
':password, :enabled, :domain_id);',
{'id': user.id,
'name': user.name,
'extra': user.extra,
'password': user.password,
'enabled': user.enabled,
'domain_id': CONF.identity.default_domain_id})
_enable_foreign_constraints(session, migrate_engine)
session.execute('drop table temp_user;')
def upgrade_project_table_with_copy(meta, migrate_engine, session):
# We want to add the domain_id attribute to the project table. Since
# it is non nullable and the table may have data, easiest way is
# a table copy. Further, in order to keep foreign key constraints
# pointing at the right table, we need to be able and do a table
# DROP then CREATE, rather than ALTERing the name of the table.
# Fist make a copy of the project table
temp_project_table = sql.Table(
'temp_project',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), unique=True, nullable=False),
sql.Column('extra', sql.Text()),
sql.Column('description', sql.Text()),
sql.Column('enabled', sql.Boolean, default=True))
temp_project_table.create(migrate_engine, checkfirst=True)
project_table = sql.Table('project', meta, autoload=True)
for project in session.query(project_table):
session.execute('insert into temp_project (id, name, extra, '
'description, enabled) '
'values ( :id, :name, :extra, '
':description, :enabled);',
{'id': project.id,
'name': project.name,
'extra': project.extra,
'description': project.description,
'enabled': project.enabled})
# Now switch off constraints while we drop and then re-create the
# project table, with the additional domain_id column
_disable_foreign_constraints(session, migrate_engine)
session.execute('drop table project;')
# Need to create a new metadata stream since we are going to load a
# different version of the project table
meta2 = sql.MetaData()
meta2.bind = migrate_engine
sql.Table('domain', meta2, autoload=True)
project_table = sql.Table(
'project',
meta2,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), nullable=False),
sql.Column('extra', sql.Text()),
sql.Column('description', sql.Text()),
sql.Column('enabled', sql.Boolean, default=True),
sql.Column('domain_id', sql.String(64), sql.ForeignKey('domain.id'),
nullable=False),
sql.UniqueConstraint('domain_id', 'name'))
project_table.create(migrate_engine, checkfirst=True)
# Finally copy in the data from our temp table and then clean
# up by deleting our temp table
for project in session.query(temp_project_table):
session.execute('insert into project (id, name, extra, '
'description, enabled, domain_id) '
'values ( :id, :name, :extra, '
':description, :enabled, :domain_id);',
{'id': project.id,
'name': project.name,
'extra': project.extra,
'description': project.description,
'enabled': project.enabled,
'domain_id': CONF.identity.default_domain_id})
_enable_foreign_constraints(session, migrate_engine)
session.execute('drop table temp_project;')
def downgrade_user_table_with_copy(meta, migrate_engine, session):
# For engines that don't support dropping columns, we need to do this
# as a table copy. Further, in order to keep foreign key constraints
# pointing at the right table, we need to be able and do a table
# DROP then CREATE, rather than ALTERing the name of the table.
# Fist make a copy of the user table
temp_user_table = sql.Table(
'temp_user',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), unique=True, nullable=False),
sql.Column('password', sql.String(128)),
sql.Column('enabled', sql.Boolean, default=True),
sql.Column('extra', sql.Text()))
temp_user_table.create(migrate_engine, checkfirst=True)
user_table = sql.Table('user', meta, autoload=True)
for user in session.query(user_table):
session.execute('insert into temp_user (id, name, '
'password, enabled, extra) '
'values ( :id, :name, '
':password, :enabled, :extra);',
{'id': user.id,
'name': user.name,
'password': user.password,
'enabled': user.enabled,
'extra': user.extra})
# Now switch off constraints while we drop and then re-create the
# user table, less the columns we wanted to drop
_disable_foreign_constraints(session, migrate_engine)
session.execute('drop table user;')
# Need to create a new metadata stream since we are going to load a
# different version of the user table
meta2 = sql.MetaData()
meta2.bind = migrate_engine
user_table = sql.Table(
'user',
meta2,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), unique=True, nullable=False),
sql.Column('extra', sql.Text()),
sql.Column('password', sql.String(128)),
sql.Column('enabled', sql.Boolean, default=True))
user_table.create(migrate_engine, checkfirst=True)
_enable_foreign_constraints(session, migrate_engine)
# Finally copy in the data from our temp table and then clean
# up by deleting our temp table
for user in session.query(temp_user_table):
session.execute('insert into user (id, name, extra, '
'password, enabled) '
'values ( :id, :name, :extra, '
':password, :enabled);',
{'id': user.id,
'name': user.name,
'extra': user.extra,
'password': user.password,
'enabled': user.enabled})
session.execute('drop table temp_user;')
def downgrade_project_table_with_copy(meta, migrate_engine, session):
# For engines that don't support dropping columns, we need to do this
# as a table copy. Further, in order to keep foreign key constraints
# pointing at the right table, we need to be able and do a table
# DROP then CREATE, rather than ALTERing the name of the table.
# Fist make a copy of the project table
temp_project_table = sql.Table(
'temp_project',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), unique=True, nullable=False),
sql.Column('description', sql.Text()),
sql.Column('enabled', sql.Boolean, default=True),
sql.Column('extra', sql.Text()))
temp_project_table.create(migrate_engine, checkfirst=True)
project_table = sql.Table('project', meta, autoload=True)
for project in session.query(project_table):
session.execute('insert into temp_project (id, name, '
'description, enabled, extra) '
'values ( :id, :name, '
':description, :enabled, :extra);',
{'id': project.id,
'name': project.name,
'description': project.description,
'enabled': project.enabled,
'extra': project.extra})
# Now switch off constraints while we drop and then re-create the
# project table, less the columns we wanted to drop
_disable_foreign_constraints(session, migrate_engine)
session.execute('drop table project;')
# Need to create a new metadata stream since we are going to load a
# different version of the project table
meta2 = sql.MetaData()
meta2.bind = migrate_engine
project_table = sql.Table(
'project',
meta2,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('name', sql.String(64), unique=True, nullable=False),
sql.Column('extra', sql.Text()),
sql.Column('description', sql.Text()),
sql.Column('enabled', sql.Boolean, default=True))
project_table.create(migrate_engine, checkfirst=True)
_enable_foreign_constraints(session, migrate_engine)
# Finally copy in the data from our temp table and then clean
# up by deleting our temp table
for project in session.query(temp_project_table):
session.execute('insert into project (id, name, extra, '
'description, enabled) '
'values ( :id, :name, :extra, '
':description, :enabled);',
{'id': project.id,
'name': project.name,
'extra': project.extra,
'description': project.description,
'enabled': project.enabled})
session.execute("drop table temp_project;")
def upgrade_user_table_with_col_create(meta, migrate_engine, session):
# Create the domain_id column. We want this to be not nullable
# but also a foreign key. We can't create this right off the
# bat since any existing rows would cause an Integrity Error.
# We therefore create it nullable, fill the column with the
# default data and then set it to non nullable.
sql.Table('domain', meta, autoload=True)
user_table = sql.Table('user', meta, autoload=True)
user_table.create_column(
sql.Column('domain_id', sql.String(64),
sql.ForeignKey('domain.id'), nullable=True))
for user in session.query(user_table).all():
values = {'domain_id': CONF.identity.default_domain_id}
update = user_table.update().\
where(user_table.c.id == user.id).\
values(values)
migrate_engine.execute(update)
# Need to commit this or setting nullable to False will fail
session.commit()
user_table.columns.domain_id.alter(nullable=False)
# Finally, change the uniqueness settings for the name attribute
session.execute('ALTER TABLE "user" DROP CONSTRAINT user_name_key;')
session.execute('ALTER TABLE "user" ADD CONSTRAINT user_dom_name_unique '
'UNIQUE (domain_id, name);')
session.commit()
def upgrade_project_table_with_col_create(meta, migrate_engine, session):
# Create the domain_id column. We want this to be not nullable
# but also a foreign key. We can't create this right off the
# bat since any existing rows would cause an Integrity Error.
# We therefore create it nullable, fill the column with the
# default data and then set it to non nullable.
sql.Table('domain', meta, autoload=True)
project_table = sql.Table('project', meta, autoload=True)
project_table.create_column(
sql.Column('domain_id', sql.String(64),
sql.ForeignKey('domain.id'), nullable=True))
for project in session.query(project_table).all():
values = {'domain_id': CONF.identity.default_domain_id}
update = project_table.update().\
where(project_table.c.id == project.id).\
values(values)
migrate_engine.execute(update)
# Need to commit this or setting nullable to False will fail
session.commit()
project_table.columns.domain_id.alter(nullable=False)
# Finally, change the uniqueness settings for the name attribute
session.execute('ALTER TABLE project DROP CONSTRAINT tenant_name_key;')
session.execute('ALTER TABLE project ADD CONSTRAINT proj_dom_name_unique '
'UNIQUE (domain_id, name);')
def downgrade_user_table_with_col_drop(meta, migrate_engine, session):
# Revert uniqueness settings for the name attribute
session.execute('ALTER TABLE "user" DROP CONSTRAINT '
'user_dom_name_unique;')
# specify the constraint name so it can be referenced later
session.execute('ALTER TABLE "user" ADD CONSTRAINT user_name_key '
'UNIQUE (name);')
session.commit()
# And now go ahead an drop the domain_id column
sql.Table('domain', meta, autoload=True)
user_table = sql.Table('user', meta, autoload=True)
column = sql.Column('domain_id', sql.String(64),
sql.ForeignKey('domain.id'), nullable=False)
column.drop(user_table)
def downgrade_project_table_with_col_drop(meta, migrate_engine, session):
# Revert uniqueness settings for the name attribute
session.execute('ALTER TABLE project DROP CONSTRAINT '
'proj_dom_name_unique;')
session.execute('ALTER TABLE project ADD CONSTRAINT tenant_name_key '
'UNIQUE (name);')
session.commit()
# And now go ahead an drop the domain_id column
sql.Table('domain', meta, autoload=True)
project_table = sql.Table('project', meta, autoload=True)
column = sql.Column('domain_id', sql.String(64),
sql.ForeignKey('domain.id'), nullable=False)
column.drop(project_table)
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
session = sessionmaker(bind=migrate_engine)()
if migrate_engine.name in ['sqlite', 'mysql']:
upgrade_user_table_with_copy(meta, migrate_engine, session)
upgrade_project_table_with_copy(meta, migrate_engine, session)
else:
upgrade_user_table_with_col_create(meta, migrate_engine, session)
upgrade_project_table_with_col_create(meta, migrate_engine, session)
session.commit()
session.close()
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
session = sessionmaker(bind=migrate_engine)()
if migrate_engine.name in ['sqlite', 'mysql']:
downgrade_user_table_with_copy(meta, migrate_engine, session)
downgrade_project_table_with_copy(meta, migrate_engine, session)
else:
# MySQL should in theory be able to use this path, but seems to
# have problems dropping columns which are foreign keys
downgrade_user_table_with_col_drop(meta, migrate_engine, session)
downgrade_project_table_with_col_drop(meta, migrate_engine, session)
session.commit()
session.close()
@@ -1,113 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import sqlalchemy as sql
from keystone import config
CONF = config.CONF
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
sql.Table('user', meta, autoload=True)
sql.Table('project', meta, autoload=True)
role_table = sql.Table('role', meta, autoload=True)
user_project_role_table = sql.Table(
'user_project_metadata',
meta,
sql.Column('user_id',
sql.String(64),
sql.ForeignKey('user.id'),
primary_key=True),
sql.Column('project_id',
sql.String(64),
sql.ForeignKey('project.id'),
primary_key=True),
sql.Column('data', sql.Text()))
user_project_role_table.create(migrate_engine, checkfirst=True)
conn = migrate_engine.connect()
conn.execute(role_table.insert(),
id=CONF.member_role_id,
name=CONF.member_role_name,
extra=json.dumps({'description':
'Default role for project membership',
'enabled': 'True'}))
user_project_membership_table = sql.Table('user_project_membership',
meta, autoload=True)
session = sql.orm.sessionmaker(bind=migrate_engine)()
for membership in session.query(user_project_membership_table):
data = {'roles': [config.CONF.member_role_id]}
ins = user_project_role_table.insert().values(
user_id=membership.user_id,
project_id=membership.tenant_id,
data=json.dumps(data))
conn.execute(ins)
session.close()
user_project_membership_table.drop()
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
sql.Table('user', meta, autoload=True)
sql.Table('project', meta, autoload=True)
user_project_membership_table = sql.Table(
'user_project_membership',
meta,
sql.Column(
'user_id',
sql.String(64),
sql.ForeignKey('user.id'),
primary_key=True),
sql.Column(
'tenant_id',
sql.String(64),
sql.ForeignKey('project.id'),
primary_key=True))
user_project_membership_table.create(migrate_engine, checkfirst=True)
user_project_metadata_table = sql.Table(
'user_project_metadata',
meta,
autoload=True)
session = sql.orm.sessionmaker(bind=migrate_engine)()
for membership in session.query(user_project_metadata_table):
if 'roles' in membership:
roles = membership['roles']
if config.CONF.member_role_id in roles:
user_project_membership_table.insert().values(
user_id=membership.user_id,
tenant_id=membership.project_id)
session.close()
role_table = sql.Table('role', meta, autoload=True)
conn = migrate_engine.connect()
user_project_membership_table = sql.Table(
'user_project_membership', meta, autoload=True)
role_table = sql.Table('role', meta, autoload=True)
conn.execute(role_table.delete().where(role_table.c.id ==
config.CONF.member_role_id))
user_project_metadata_table.drop()
@@ -1,65 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
def upgrade(migrate_engine):
# Upgrade operations go here. Don't create your own engine; bind
# migrate_engine to your metadata
meta = sql.MetaData()
meta.bind = migrate_engine
sql.Table('user', meta, autoload=True)
sql.Table('role', meta, autoload=True)
sql.Table('project', meta, autoload=True)
trust_table = sql.Table(
'trust',
meta,
sql.Column('id', sql.String(64), primary_key=True),
sql.Column('trustor_user_id',
sql.String(64),
unique=False,
nullable=False,),
sql.Column('trustee_user_id',
sql.String(64),
unique=False,
nullable=False),
sql.Column('project_id', sql.String(64),
unique=False,
nullable=True),
sql.Column("impersonation", sql.types.Boolean, nullable=False),
sql.Column("deleted_at", sql.types.DateTime, nullable=True),
sql.Column("expires_at", sql.types.DateTime, nullable=True),
sql.Column('extra', sql.Text()))
trust_table.create(migrate_engine, checkfirst=True)
trust_role_table = sql.Table(
'trust_role',
meta,
sql.Column('trust_id', sql.String(64), primary_key=True,
nullable=False),
sql.Column('role_id', sql.String(64), primary_key=True,
nullable=False))
trust_role_table.create(migrate_engine, checkfirst=True)
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
# Operations to reverse the above upgrade go here.
for table_name in ['trust_role', 'trust']:
table = sql.Table(table_name, meta, autoload=True)
table.drop()
@@ -1,46 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
from keystone import config
CONF = config.CONF
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
role_table = sql.Table('role', meta, autoload=True)
# name should be 255 characters to match fresh database
role_table.c.name.alter(type=sql.String(length=255))
# blank 'extra' field should be "{}"
none = None
update = role_table.update().where(role_table.c.extra == none).values(
{role_table.c.extra: "{}"})
migrate_engine.execute(update)
def downgrade(migrate_engine):
# this fixes bugs in migration 001 and 007 that result in discrepancies
# between fresh databases and databases updated from 004 (folsom).
# the changes fixing 007 will be rolled back in 007's rollback if
# the user desires to return to a state before the existence of the extra
# column.
# the name length change reflects the current default and should not be
# rolled back.
pass
@@ -1,109 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import sqlalchemy as sql
from keystone import config
CONF = config.CONF
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
sql.Table('user', meta, autoload=True)
sql.Table('role', meta, autoload=True)
sql.Table('project', meta, autoload=True)
new_metadata_table = sql.Table('user_project_metadata',
meta,
autoload=True)
old_metadata_table = sql.Table('metadata', meta, autoload=True)
session = sql.orm.sessionmaker(bind=migrate_engine)()
for metadata in session.query(old_metadata_table):
data = json.loads(metadata.data)
if config.CONF.member_role_id not in metadata.data:
data['roles'].append(config.CONF.member_role_id)
r = session.query(new_metadata_table).filter_by(
user_id=metadata.user_id,
project_id=metadata.tenant_id).first()
if r is not None:
# roles should be the union of the two role lists
old_roles = data['roles']
new_roles = json.loads(r.data)['roles']
data['roles'] = list(set(old_roles) | set(new_roles))
q = new_metadata_table.update().where(
new_metadata_table.c.user_id == metadata.user_id).where(
new_metadata_table.c.project_id ==
metadata.tenant_id).values(data=json.dumps(data))
else:
q = new_metadata_table.insert().values(
user_id=metadata.user_id,
project_id=metadata.tenant_id,
data=json.dumps(data))
session.execute(q)
session.commit()
old_metadata_table.drop()
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
sql.Table('user', meta, autoload=True)
sql.Table('project', meta, autoload=True)
metadata_table = sql.Table(
'metadata',
meta,
sql.Column(
u'user_id',
sql.String(64),
primary_key=True),
sql.Column(
u'tenant_id',
sql.String(64),
primary_key=True),
sql.Column('data',
sql.Text()))
metadata_table.create(migrate_engine, checkfirst=True)
user_project_metadata_table = sql.Table(
'user_project_metadata',
meta,
autoload=True)
metadata_table = sql.Table(
'metadata',
meta,
autoload=True)
session = sql.orm.sessionmaker(bind=migrate_engine)()
for metadata in session.query(user_project_metadata_table):
if 'roles' in metadata:
metadata_table.insert().values(
user_id=metadata.user_id,
tenant_id=metadata.project_id)
session.close()
@@ -1,76 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy
from sqlalchemy import exc
def downgrade_token_table_with_column_drop(meta, migrate_engine):
token_table = sqlalchemy.Table('token', meta, autoload=True)
# delete old tokens, as the format has changed.
# We don't guarantee that existing tokens will be
# usable after a migration
token_table.delete()
token_table.drop_column(
sqlalchemy.Column('trust_id',
sqlalchemy.String(64),
nullable=True))
token_table.drop_column(
sqlalchemy.Column('user_id',
sqlalchemy.String(64)))
def create_column_forgiving(migrate_engine, table, column):
try:
table.create_column(column)
except exc.OperationalError as e:
if (e.args[0].endswith('duplicate column name: %s' % column.name)
and migrate_engine.name == "sqlite"):
# sqlite does not drop columns, so if we have already
# done a downgrade and are now upgrading, we will hit
# this: the SQLite driver previously reported success
# dropping the columns but it hasn't.
pass
else:
raise
def upgrade_token_table(meta, migrate_engine):
# delete old tokens, as the format has changed.
# The existing tokens will not
# support some of the list functions
token_table = sqlalchemy.Table('token', meta, autoload=True)
token_table.delete()
create_column_forgiving(
migrate_engine, token_table,
sqlalchemy.Column('trust_id',
sqlalchemy.String(64),
nullable=True))
create_column_forgiving(
migrate_engine, token_table,
sqlalchemy.Column('user_id', sqlalchemy.String(64)))
def upgrade(migrate_engine):
meta = sqlalchemy.MetaData()
meta.bind = migrate_engine
upgrade_token_table(meta, migrate_engine)
def downgrade(migrate_engine):
meta = sqlalchemy.MetaData()
meta.bind = migrate_engine
downgrade_token_table_with_column_drop(meta, migrate_engine)
@@ -1,68 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import sqlalchemy as sql
from sqlalchemy import orm
from keystone import config
CONF = config.CONF
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
endpoint_table = sql.Table('endpoint', meta, autoload=True)
session = orm.sessionmaker(bind=migrate_engine)()
for endpoint in session.query(endpoint_table).all():
try:
extra = json.loads(endpoint.extra)
legacy_endpoint_id = extra.pop('legacy_endpoint_id')
except KeyError:
# if there is no legacy_endpoint_id, there's nothing to do
pass
else:
q = endpoint_table.update()
q = q.where(endpoint_table.c.id == endpoint.id)
q = q.values({
endpoint_table.c.extra: json.dumps(extra),
endpoint_table.c.legacy_endpoint_id: legacy_endpoint_id})
migrate_engine.execute(q)
session.close()
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
endpoint_table = sql.Table('endpoint', meta, autoload=True)
session = orm.sessionmaker(bind=migrate_engine)()
for endpoint in session.query(endpoint_table).all():
if endpoint.legacy_endpoint_id is not None:
extra = json.loads(endpoint.extra)
extra['legacy_endpoint_id'] = endpoint.legacy_endpoint_id
q = endpoint_table.update()
q = q.where(endpoint_table.c.id == endpoint.id)
q = q.values({
endpoint_table.c.extra: json.dumps(extra),
endpoint_table.c.legacy_endpoint_id: None})
migrate_engine.execute(q)
session.close()
@@ -1,47 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
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)
proj_table = sqlalchemy.Table('project', meta, autoload=True)
cred_table = sqlalchemy.Table('credential', meta, autoload=True)
constraints = [{'table': cred_table,
'fk_column': 'user_id',
'ref_column': user_table.c.id},
{'table': cred_table,
'fk_column': 'project_id',
'ref_column': proj_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))
def downgrade(migrate_engine):
if migrate_engine.name == 'sqlite':
return
migration_helpers.add_constraints(list_constraints(migrate_engine))
@@ -1,31 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
token = sql.Table('token', meta, autoload=True)
idx = sql.Index('ix_token_expires', token.c.expires)
idx.create(migrate_engine)
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
token = sql.Table('token', meta, autoload=True)
idx = sql.Index('ix_token_expires', token.c.expires)
idx.drop(migrate_engine)
@@ -1,31 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
token = sql.Table('token', meta, autoload=True)
idx = sql.Index('ix_token_valid', token.c.valid)
idx.create(migrate_engine)
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
token = sql.Table('token', meta, autoload=True)
idx = sql.Index('ix_token_valid', token.c.valid)
idx.drop(migrate_engine)
@@ -1,60 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
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)
sqlalchemy.Table('project', meta, autoload=True)
group_table = sqlalchemy.Table('group', meta, autoload=True)
user_domain_metadata_table = sqlalchemy.Table('user_domain_metadata',
meta, autoload=True)
group_domain_metadata_table = sqlalchemy.Table('group_domain_metadata',
meta, autoload=True)
user_project_metadata_table = sqlalchemy.Table('user_project_metadata',
meta, autoload=True)
group_project_metadata_table = sqlalchemy.Table('group_project_metadata',
meta, autoload=True)
constraints = [{'table': user_domain_metadata_table,
'fk_column': 'user_id',
'ref_column': user_table.c.id},
{'table': group_domain_metadata_table,
'fk_column': 'group_id',
'ref_column': group_table.c.id},
{'table': user_project_metadata_table,
'fk_column': 'user_id',
'ref_column': user_table.c.id},
{'table': group_project_metadata_table,
'fk_column': 'group_id',
'ref_column': group_table.c.id},
]
return constraints
def upgrade(migrate_engine):
if migrate_engine.name == 'sqlite':
return
migration_helpers.remove_constraints(list_constraints(migrate_engine))
def downgrade(migrate_engine):
if migrate_engine.name == 'sqlite':
return
migration_helpers.add_constraints(list_constraints(migrate_engine))
@@ -1,156 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
from sqlalchemy import MetaData
from keystone.common.sql import migration_helpers
def upgrade(migrate_engine):
# Upgrade operations go here. Don't create your own engine;
# bind migrate_engine to your metadata
if migrate_engine.name != 'mysql':
# InnoDB / MyISAM only applies to MySQL.
return
# This is a list of all the tables that might have been created with MyISAM
# rather than InnoDB.
tables = [
'credential',
'domain',
'ec2_credential',
'endpoint',
'group',
'group_domain_metadata',
'group_project_metadata',
'policy',
'project',
'role',
'service',
'token',
'trust',
'trust_role',
'user',
'user_domain_metadata',
'user_group_membership',
'user_project_metadata',
]
meta = MetaData()
meta.bind = migrate_engine
domain_table = sql.Table('domain', meta, autoload=True)
endpoint_table = sql.Table('endpoint', meta, autoload=True)
group_table = sql.Table('group', meta, autoload=True)
group_domain_metadata_table = sql.Table('group_domain_metadata', meta,
autoload=True)
group_project_metadata_table = sql.Table('group_project_metadata', meta,
autoload=True)
project_table = sql.Table('project', meta, autoload=True)
service_table = sql.Table('service', meta, autoload=True)
user_table = sql.Table('user', meta, autoload=True)
user_domain_metadata_table = sql.Table('user_domain_metadata', meta,
autoload=True)
user_group_membership_table = sql.Table('user_group_membership', meta,
autoload=True)
# Mapping of table name to the constraints on that table,
# so we can create them.
table_constraints = {
'endpoint': [{'table': endpoint_table,
'fk_column': 'service_id',
'ref_column': service_table.c.id},
],
'group': [{'table': group_table,
'fk_column': 'domain_id',
'ref_column': domain_table.c.id},
],
'group_domain_metadata': [{'table': group_domain_metadata_table,
'fk_column': 'domain_id',
'ref_column': domain_table.c.id},
],
'group_project_metadata': [{'table': group_project_metadata_table,
'fk_column': 'project_id',
'ref_column': project_table.c.id},
],
'project': [{'table': project_table,
'fk_column': 'domain_id',
'ref_column': domain_table.c.id},
],
'user': [{'table': user_table,
'fk_column': 'domain_id',
'ref_column': domain_table.c.id},
],
'user_domain_metadata': [{'table': user_domain_metadata_table,
'fk_column': 'domain_id',
'ref_column': domain_table.c.id},
],
'user_group_membership': [{'table': user_group_membership_table,
'fk_column': 'user_id',
'ref_column': user_table.c.id},
{'table': user_group_membership_table,
'fk_column': 'group_id',
'ref_column': group_table.c.id},
],
'user_project_metadata': [{'table': group_project_metadata_table,
'fk_column': 'project_id',
'ref_column': project_table.c.id},
],
}
# Maps a table name to the tables that reference it as a FK constraint
# (See the map above).
ref_tables_map = {
'service': ['endpoint', ],
'domain': ['group', 'group_domain_metadata', 'project', 'user',
'user_domain_metadata', ],
'project': ['group_project_metadata', 'user_project_metadata', ],
'user': ['user_group_membership', ],
'group': ['user_group_membership', ],
}
# The names of tables that need to have their FKs added.
fk_table_names = set()
d = migrate_engine.execute("SHOW TABLE STATUS WHERE Engine!='InnoDB';")
for row in d.fetchall():
table_name = row[0]
if table_name not in tables:
# Skip this table since it's not a Keystone table.
continue
migrate_engine.execute("ALTER TABLE `%s` Engine=InnoDB" % table_name)
# Will add the FKs to the table if any of
# a) the table itself was converted
# b) the tables that the table referenced were converted
if table_name in table_constraints:
fk_table_names.add(table_name)
ref_tables = ref_tables_map.get(table_name, [])
for other_table_name in ref_tables:
fk_table_names.add(other_table_name)
# Now add all the FK constraints to those tables
for table_name in fk_table_names:
constraints = table_constraints.get(table_name)
migration_helpers.add_constraints(constraints)
def downgrade(migrate_engine):
pass
@@ -1,188 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
def upgrade(migrate_engine):
# The group_project_metadata table was not updated in terms of its
# FK to the tenant table when the tenant->project change was made at
# the 015 migration for sqlite. This upgrade fixes that.
# We need to create a fake tenant table so that we can first load
# the group_project_metadata at all, then do a dance of copying tables
# to get us to the correct schema.
meta = sql.MetaData()
meta.bind = migrate_engine
if migrate_engine.name != 'sqlite':
return
temp_tenant_table = sql.Table(
'tenant',
meta,
sql.Column('id', sql.String(64), primary_key=True))
temp_tenant_table.create(migrate_engine, checkfirst=True)
sql.Table('user', meta, autoload=True)
old_group_metadata_table = sql.Table('group_project_metadata',
meta, autoload=True)
# OK, we now have the table loaded, create a first
# temporary table of a different name with the correct FK
sql.Table('project', meta, autoload=True)
temp_group_project_metadata_table = sql.Table(
'temp_group_project_metadata',
meta,
sql.Column(
'group_id',
sql.String(64),
primary_key=True),
sql.Column(
'project_id',
sql.String(64),
sql.ForeignKey('project.id'),
primary_key=True),
sql.Column('data', sql.Text()))
temp_group_project_metadata_table.create(migrate_engine, checkfirst=True)
# Populate the new temporary table, and then drop the old one
session = sql.orm.sessionmaker(bind=migrate_engine)()
for metadata in session.query(old_group_metadata_table):
q = temp_group_project_metadata_table.insert().values(
group_id=metadata.group_id,
project_id=metadata.project_id,
data=metadata.data)
session.execute(q)
session.commit()
old_group_metadata_table.drop()
temp_tenant_table.drop()
# Now do a final table copy to get the table of the right name.
# Re-init the metadata so that sqlalchemy does not get confused with
# multiple versions of the same named table.
meta2 = sql.MetaData()
meta2.bind = migrate_engine
sql.Table('project', meta2, autoload=True)
new_group_project_metadata_table = sql.Table(
'group_project_metadata',
meta2,
sql.Column(
'group_id',
sql.String(64),
primary_key=True),
sql.Column(
'project_id',
sql.String(64),
sql.ForeignKey('project.id'),
primary_key=True),
sql.Column('data', sql.Text()))
new_group_project_metadata_table.create(migrate_engine, checkfirst=True)
for metadata in session.query(temp_group_project_metadata_table):
q = new_group_project_metadata_table.insert().values(
group_id=metadata.group_id,
project_id=metadata.project_id,
data=metadata.data)
session.execute(q)
session.commit()
temp_group_project_metadata_table.drop()
def downgrade(migrate_engine):
# Put the group_project_metadata table back the way it was in its rather
# broken state. We don't try and re-write history, since otherwise people
# get out of step.
meta = sql.MetaData()
meta.bind = migrate_engine
if migrate_engine.name != 'sqlite':
return
sql.Table('user', meta, autoload=True)
sql.Table('project', meta, autoload=True)
group_metadata_table = sql.Table('group_project_metadata',
meta, autoload=True)
# We want to create a temp group meta table with the FK
# set to the wrong place.
temp_tenant_table = sql.Table(
'tenant',
meta,
sql.Column('id', sql.String(64), primary_key=True))
temp_tenant_table.create(migrate_engine, checkfirst=True)
temp_group_project_metadata_table = sql.Table(
'temp_group_project_metadata',
meta,
sql.Column(
'group_id',
sql.String(64),
primary_key=True),
sql.Column(
'project_id',
sql.String(64),
sql.ForeignKey('tenant.id'),
primary_key=True),
sql.Column('data', sql.Text()))
temp_group_project_metadata_table.create(migrate_engine, checkfirst=True)
# Now populate the temp table and drop the real one
session = sql.orm.sessionmaker(bind=migrate_engine)()
for metadata in session.query(group_metadata_table):
q = temp_group_project_metadata_table.insert().values(
group_id=metadata.group_id,
project_id=metadata.project_id,
data=metadata.data)
session.execute(q)
session.commit()
group_metadata_table.drop()
# Now copy again into the correctly named table. Re-init the metadata
# so that sqlalchemy does not get confused with multiple versions of the
# same named table.
meta2 = sql.MetaData()
meta2.bind = migrate_engine
sql.Table('tenant', meta2, autoload=True)
new_group_project_metadata_table = sql.Table(
'group_project_metadata',
meta2,
sql.Column(
'group_id',
sql.String(64),
primary_key=True),
sql.Column(
'project_id',
sql.String(64),
sql.ForeignKey('tenant.id'),
primary_key=True),
sql.Column('data', sql.Text()))
new_group_project_metadata_table.create(migrate_engine, checkfirst=True)
for metadata in session.query(temp_group_project_metadata_table):
q = new_group_project_metadata_table.insert().values(
group_id=metadata.group_id,
project_id=metadata.project_id,
data=metadata.data)
session.execute(q)
session.commit()
temp_group_project_metadata_table.drop()
temp_tenant_table.drop()
@@ -1,100 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import sqlalchemy as sql
def build_update(table_name, upgrade_table, row, values):
if table_name == 'user_project_metadata':
update = upgrade_table.update().where(
upgrade_table.c.user_id == row.user_id).where(
upgrade_table.c.project_id == row.project_id).values(values)
elif table_name == 'group_project_metadata':
update = upgrade_table.update().where(
upgrade_table.c.group_id == row.group_id).where(
upgrade_table.c.project_id == row.project_id).values(values)
elif table_name == 'user_domain_metadata':
update = upgrade_table.update().where(
upgrade_table.c.user_id == row.user_id).where(
upgrade_table.c.domain_id == row.domain_id).values(values)
else:
update = upgrade_table.update().where(
upgrade_table.c.group_id == row.group_id).where(
upgrade_table.c.domain_id == row.domain_id).values(values)
return update
def upgrade_grant_table(meta, migrate_engine, session, table_name):
# Convert the roles component of the metadata from a list
# of ids to a list of dicts
def list_to_dict_list(metadata):
json_metadata = json.loads(metadata)
if 'roles' in json_metadata:
json_metadata['roles'] = (
[{'id': x} for x in json_metadata['roles']])
return json.dumps(json_metadata)
upgrade_table = sql.Table(table_name, meta, autoload=True)
for assignment in session.query(upgrade_table):
values = {'data': list_to_dict_list(assignment.data)}
update = build_update(table_name, upgrade_table, assignment, values)
migrate_engine.execute(update)
def downgrade_grant_table(meta, migrate_engine, session, table_name):
# Convert the roles component of the metadata from a list
# of dicts to a simple list of ids. Any inherited roles are deleted
# since they would have no meaning
def dict_list_to_list(metadata):
json_metadata = json.loads(metadata)
if 'roles' in json_metadata:
json_metadata['roles'] = ([x['id'] for x in json_metadata['roles']
if 'inherited_to' not in x])
return json.dumps(json_metadata)
downgrade_table = sql.Table(table_name, meta, autoload=True)
for assignment in session.query(downgrade_table):
values = {'data': dict_list_to_list(assignment.data)}
update = build_update(table_name, downgrade_table, assignment, values)
migrate_engine.execute(update)
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
session = sql.orm.sessionmaker(bind=migrate_engine)()
for grant_table in ['user_project_metadata', 'user_domain_metadata',
'group_project_metadata', 'group_domain_metadata']:
upgrade_grant_table(meta, migrate_engine, session, grant_table)
session.commit()
session.close()
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
session = sql.orm.sessionmaker(bind=migrate_engine)()
for grant_table in ['user_project_metadata', 'user_domain_metadata',
'group_project_metadata', 'group_domain_metadata']:
downgrade_grant_table(meta, migrate_engine, session, grant_table)
session.commit()
session.close()
@@ -1,116 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy
from sqlalchemy.orm import sessionmaker
def upgrade(migrate_engine):
if migrate_engine.name == 'sqlite':
drop_credential_table_foreign_key_constraints_for_sqlite(
migrate_engine)
def downgrade(migrate_engine):
if migrate_engine.name == 'sqlite':
add_credential_table_foreign_key_constraints_for_sqlite(migrate_engine)
def drop_credential_table_foreign_key_constraints_for_sqlite(migrate_engine):
meta = sqlalchemy.MetaData()
meta.bind = migrate_engine
# NOTE(nachiappan): SQLite does not support ALTER TABLE DROP constraint.
# So we need to move the data to new credenital table
# created without constraints, drop the old table and
# rename the new table to credential.
sqlalchemy.Table('user', meta, autoload=True)
tenant_table = sqlalchemy.Table(
'tenant',
meta,
sqlalchemy.Column('id', sqlalchemy.String(64), primary_key=True),
sqlalchemy.Column(
'name', sqlalchemy.String(64), unique=True, nullable=False),
sqlalchemy.Column('extra', sqlalchemy.Text()))
tenant_table.create(migrate_engine, checkfirst=True)
cred_table = sqlalchemy.Table('credential', meta, autoload=True)
session = sessionmaker(bind=migrate_engine)()
new_credential_table = sqlalchemy.Table(
'new_credential',
meta,
sqlalchemy.Column('id', sqlalchemy.String(64), primary_key=True),
sqlalchemy.Column('user_id',
sqlalchemy.String(64),
nullable=False),
sqlalchemy.Column('project_id',
sqlalchemy.String(64)),
sqlalchemy.Column('blob', sqlalchemy.Text(), nullable=False),
sqlalchemy.Column('type', sqlalchemy.String(255), nullable=False),
sqlalchemy.Column('extra', sqlalchemy.Text()))
new_credential_table.create(migrate_engine, checkfirst=True)
insert = new_credential_table.insert()
for credential in session.query(cred_table):
insert.execute({'id': credential.id,
'user_id': credential.user_id,
'project_id': credential.project_id,
'blob': credential.blob,
'type': credential.type,
'extra': credential.extra})
cred_table.drop()
tenant_table.drop()
new_credential_table.rename('credential')
session.commit()
session.close()
def add_credential_table_foreign_key_constraints_for_sqlite(migrate_engine):
meta = sqlalchemy.MetaData()
meta.bind = migrate_engine
cred_table = sqlalchemy.Table('credential', meta, autoload=True)
sqlalchemy.Table('user', meta, autoload=True)
session = sessionmaker(bind=migrate_engine)()
old_credential_table = sqlalchemy.Table(
'old_credential',
meta,
sqlalchemy.Column('id', sqlalchemy.String(64), primary_key=True),
sqlalchemy.Column('user_id',
sqlalchemy.String(64),
sqlalchemy.ForeignKey('user.id'),
nullable=False),
# NOTE(nachiappan): Not creating the foreign key constraint with
# project table as version 15 conflicts with
# version 7.
sqlalchemy.Column('project_id',
sqlalchemy.String(64)),
sqlalchemy.Column('blob', sqlalchemy.Text(), nullable=False),
sqlalchemy.Column('type', sqlalchemy.String(255), nullable=False),
sqlalchemy.Column('extra', sqlalchemy.Text()))
old_credential_table.create(migrate_engine, checkfirst=True)
insert = old_credential_table.insert()
for credential in session.query(cred_table):
insert.execute({'id': credential.id,
'user_id': credential.user_id,
'project_id': credential.project_id,
'blob': credential.blob,
'type': credential.type,
'extra': credential.extra})
cred_table.drop()
old_credential_table.rename('credential')
session.commit()
session.close()
@@ -1,38 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy
def upgrade(migrate_engine):
# This migration is relevant only for mysql because for all other
# migrate engines these indexes were successfully dropped.
if migrate_engine.name != 'mysql':
return
meta = sqlalchemy.MetaData(bind=migrate_engine)
table = sqlalchemy.Table('credential', meta, autoload=True)
for index in table.indexes:
index.drop()
def downgrade(migrate_engine):
if migrate_engine.name != 'mysql':
return
meta = sqlalchemy.MetaData(bind=migrate_engine)
table = sqlalchemy.Table('credential', meta, autoload=True)
index = sqlalchemy.Index('user_id', table.c['user_id'])
index.create()
index = sqlalchemy.Index('credential_project_id_fkey',
table.c['project_id'])
index.create()
@@ -1,45 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
from sqlalchemy.orm import sessionmaker
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
user_table = sql.Table('user', meta, autoload=True)
user_table.c.name.alter(type=sql.String(255))
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
user_table = sql.Table('user', meta, autoload=True)
if migrate_engine.name != 'mysql':
# NOTE(aloga): sqlite does not enforce length on the
# VARCHAR types: http://www.sqlite.org/faq.html#q9
# postgresql and DB2 do not truncate.
maker = sessionmaker(bind=migrate_engine)
session = maker()
for user in session.query(user_table).all():
values = {'name': user.name[:64]}
update = (user_table.update().
where(user_table.c.id == user.id).
values(values))
migrate_engine.execute(update)
session.commit()
session.close()
user_table.c.name.alter(type=sql.String(64))
@@ -1,110 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sql
from keystone.common import utils
from keystone import exception
from keystone.openstack.common.gettextutils import _
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
credential_table = sql.Table('credential',
meta,
autoload=True)
ec2_cred_table = sql.Table('ec2_credential',
meta,
autoload=True)
session = sql.orm.sessionmaker(bind=migrate_engine)()
insert = credential_table.insert()
for ec2credential in session.query(ec2_cred_table):
cred_exist = check_credential_exists(ec2credential,
credential_table, session)
if not cred_exist:
credential = utils.convert_ec2_to_v3_credential(ec2credential)
insert.execute(credential)
session.commit()
session.close()
ec2_cred_table.drop()
def check_credential_exists(ec2credential, credential_table, session):
credential = session.query(credential_table).filter_by(
id=utils.hash_access_key(ec2credential.access)).first()
if credential is None:
return False
blob = utils.get_blob_from_credential(credential)
# check if credential with same access key but different
# secret key already exists in credential table.
# If exists raise an exception
if blob['secret'] != ec2credential.secret:
msg = _('Credential %(access)s already exists with different secret'
' in %(table)s table')
message = msg % {'access': ec2credential.access,
'table': credential_table.name}
raise exception.Conflict(type='credential', details=message)
# check if credential with same access and secret key but
# associated with a different project exists. If exists raise
# an exception
elif credential.project_id is not None and (
credential.project_id != ec2credential.tenant_id):
msg = _('Credential %(access)s already exists with different project'
' in %(table)s table')
message = msg % {'access': ec2credential.access,
'table': credential_table.name}
raise exception.Conflict(type='credential', details=message)
# if credential with same access and secret key and not associated
# with any projects already exists in the credential table, then
# return true.
else:
return True
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
session = sql.orm.sessionmaker(bind=migrate_engine)()
ec2_credential_table = sql.Table(
'ec2_credential',
meta,
sql.Column('access', sql.String(64), primary_key=True),
sql.Column('secret', sql.String(64)),
sql.Column('user_id', sql.String(64)),
sql.Column('tenant_id', sql.String(64)),
mysql_engine='InnoDB',
mysql_charset='utf8')
ec2_credential_table.create(migrate_engine, checkfirst=True)
credential_table = sql.Table('credential',
meta,
autoload=True)
insert = ec2_credential_table.insert()
for credential in session.query(credential_table).filter(
sql.and_(credential_table.c.type == 'ec2',
credential_table.c.project_id is not None)).all():
ec2_credential = utils.convert_v3_to_ec2_credential(credential)
insert.execute(ec2_credential)
session.commit()
session.close()
@@ -1,102 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import sqlalchemy as sql
from sqlalchemy.orm import sessionmaker
def migrate_default_project_from_extra_json(meta, migrate_engine):
user_table = sql.Table('user', meta, autoload=True)
user_list = list(user_table.select().execute())
session = sessionmaker(bind=migrate_engine)()
for user in user_list:
try:
data = json.loads(user.extra)
default_project_id = data.pop('default_project_id', None)
v2_tenant_id = data.pop('tenantId', None)
alt_v2_tenant_id = data.pop('tenant_id', None)
except (ValueError, TypeError):
# NOTE(morganfainberg): Somehow we have non-json data here. This
# is a broken user, but it was broken beforehand. Cleaning it up
# is not in the scope of this migration.
continue
values = {}
if default_project_id is not None:
values['default_project_id'] = default_project_id
elif v2_tenant_id is not None:
values['default_project_id'] = v2_tenant_id
elif alt_v2_tenant_id is not None:
values['default_project_id'] = alt_v2_tenant_id
if 'default_project_id' in values:
values['extra'] = json.dumps(data)
update = user_table.update().where(
user_table.c.id == user['id']).values(values)
migrate_engine.execute(update)
session.commit()
session.close()
def migrate_default_project_to_extra_json(meta, migrate_engine):
user_table = sql.Table('user', meta, autoload=True)
user_list = list(user_table.select().execute())
session = sessionmaker(bind=migrate_engine)()
for user in user_list:
try:
data = json.loads(user.extra)
except (ValueError, TypeError):
# NOTE(morganfainberg): Somehow we have non-json data here. This
# is a broken user, but it was broken beforehand. Cleaning it up
# is not in the scope of this migration.
continue
# NOTE(morganfainberg): We don't really know what the original 'extra'
# property was here. Populate all of the possible variants we may have
# originally used.
if user.default_project_id is not None:
data['default_project_id'] = user.default_project_id
data['tenantId'] = user.default_project_id
data['tenant_id'] = user.default_project_id
values = {'extra': json.dumps(data)}
update = user_table.update().where(
user_table.c.id == user.id).values(values)
migrate_engine.execute(update)
session.commit()
session.close()
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
user_table = sql.Table('user', meta, autoload=True)
default_project_id = sql.Column('default_project_id', sql.String(64))
user_table.create_column(default_project_id)
migrate_default_project_from_extra_json(meta, migrate_engine)
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
migrate_default_project_to_extra_json(meta, migrate_engine)
user_table = sql.Table('user', meta, autoload=True)
user_table.drop_column('default_project_id')
@@ -1,31 +0,0 @@
# Copyright 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.
import sqlalchemy as sql
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
token = sql.Table('token', meta, autoload=True)
idx = sql.Index('ix_token_expires_valid', token.c.expires, token.c.valid)
idx.create(migrate_engine)
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
token = sql.Table('token', meta, autoload=True)
idx = sql.Index('ix_token_expires_valid', token.c.expires, token.c.valid)
idx.drop(migrate_engine)
@@ -0,0 +1,288 @@
# 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 orm
from keystone.common import sql as ks_sql
from keystone.common.sql import migration_helpers
from keystone import config
from keystone.openstack.common import log
LOG = log.getLogger(__name__)
CONF = config.CONF
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
if migrate_engine.name == 'mysql':
# In Folsom we explicitly converted migrate_version to UTF8.
sql_stmt = 'ALTER TABLE migrate_version CONVERT TO CHARACTER SET utf8;'
# Set default DB charset to UTF8.
sql_stmt += ('ALTER DATABASE %s DEFAULT CHARACTER SET utf8;' %
migrate_engine.url.database)
migrate_engine.execute(sql_stmt)
credential = sql.Table(
'credential', meta,
sql.Column('id', sql.String(length=64), primary_key=True),
sql.Column('user_id', sql.String(length=64), nullable=False),
sql.Column('project_id', sql.String(length=64)),
sql.Column('blob', ks_sql.JsonBlob, nullable=False),
sql.Column('type', sql.String(length=255), nullable=False),
sql.Column('extra', ks_sql.JsonBlob.impl),
mysql_engine='InnoDB',
mysql_charset='utf8')
domain = sql.Table(
'domain', meta,
sql.Column('id', sql.String(length=64), primary_key=True),
sql.Column('name', sql.String(length=64), nullable=False),
sql.Column('enabled', sql.Boolean, default=True, nullable=False),
sql.Column('extra', ks_sql.JsonBlob.impl),
mysql_engine='InnoDB',
mysql_charset='utf8')
endpoint = sql.Table(
'endpoint', meta,
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),
mysql_engine='InnoDB',
mysql_charset='utf8')
group = sql.Table(
'group', meta,
sql.Column('id', sql.String(length=64), primary_key=True),
sql.Column('domain_id', sql.String(length=64), nullable=False),
sql.Column('name', sql.String(length=64), nullable=False),
sql.Column('description', sql.Text),
sql.Column('extra', ks_sql.JsonBlob.impl),
mysql_engine='InnoDB',
mysql_charset='utf8')
group_domain_metadata = sql.Table(
'group_domain_metadata', meta,
sql.Column('group_id', sql.String(length=64), primary_key=True),
sql.Column('domain_id', sql.String(length=64), primary_key=True),
sql.Column('data', ks_sql.JsonBlob.impl),
mysql_engine='InnoDB',
mysql_charset='utf8')
group_project_metadata = sql.Table(
'group_project_metadata', meta,
sql.Column('group_id', sql.String(length=64), primary_key=True),
sql.Column('project_id', sql.String(length=64), primary_key=True),
sql.Column('data', ks_sql.JsonBlob.impl),
mysql_engine='InnoDB',
mysql_charset='utf8')
policy = sql.Table(
'policy', meta,
sql.Column('id', sql.String(length=64), primary_key=True),
sql.Column('type', sql.String(length=255), nullable=False),
sql.Column('blob', ks_sql.JsonBlob, nullable=False),
sql.Column('extra', ks_sql.JsonBlob.impl),
mysql_engine='InnoDB',
mysql_charset='utf8')
project = sql.Table(
'project', meta,
sql.Column('id', sql.String(length=64), primary_key=True),
sql.Column('name', sql.String(length=64), nullable=False),
sql.Column('extra', ks_sql.JsonBlob.impl),
sql.Column('description', sql.Text),
sql.Column('enabled', sql.Boolean),
sql.Column('domain_id', sql.String(length=64), nullable=False),
mysql_engine='InnoDB',
mysql_charset='utf8')
role = sql.Table(
'role', meta,
sql.Column('id', sql.String(length=64), primary_key=True),
sql.Column('name', sql.String(length=255), nullable=False),
sql.Column('extra', ks_sql.JsonBlob.impl),
mysql_engine='InnoDB',
mysql_charset='utf8')
service = sql.Table(
'service', meta,
sql.Column('id', sql.String(length=64), primary_key=True),
sql.Column('type', sql.String(length=255)),
sql.Column('extra', ks_sql.JsonBlob.impl),
mysql_engine='InnoDB',
mysql_charset='utf8')
token = sql.Table(
'token', meta,
sql.Column('id', sql.String(length=64), primary_key=True),
sql.Column('expires', sql.DateTime, default=None),
sql.Column('extra', ks_sql.JsonBlob.impl),
sql.Column('valid', sql.Boolean, default=True, nullable=False),
sql.Column('trust_id', sql.String(length=64)),
sql.Column('user_id', sql.String(length=64)),
mysql_engine='InnoDB',
mysql_charset='utf8')
trust = sql.Table(
'trust', meta,
sql.Column('id', sql.String(length=64), primary_key=True),
sql.Column('trustor_user_id', sql.String(length=64), nullable=False),
sql.Column('trustee_user_id', sql.String(length=64), nullable=False),
sql.Column('project_id', sql.String(length=64)),
sql.Column('impersonation', sql.Boolean, nullable=False),
sql.Column('deleted_at', sql.DateTime),
sql.Column('expires_at', sql.DateTime),
sql.Column('extra', ks_sql.JsonBlob.impl),
mysql_engine='InnoDB',
mysql_charset='utf8')
trust_role = sql.Table(
'trust_role', meta,
sql.Column('trust_id', sql.String(length=64), primary_key=True,
nullable=False),
sql.Column('role_id', sql.String(length=64), primary_key=True,
nullable=False),
mysql_engine='InnoDB',
mysql_charset='utf8')
user = sql.Table(
'user', meta,
sql.Column('id', sql.String(length=64), primary_key=True),
sql.Column('name', sql.String(length=255), nullable=False),
sql.Column('extra', ks_sql.JsonBlob.impl),
sql.Column('password', sql.String(length=128)),
sql.Column('enabled', sql.Boolean),
sql.Column('domain_id', sql.String(length=64), nullable=False),
sql.Column('default_project_id', sql.String(length=64)),
mysql_engine='InnoDB',
mysql_charset='utf8')
user_domain_metadata = sql.Table(
'user_domain_metadata', meta,
sql.Column('user_id', sql.String(length=64), primary_key=True),
sql.Column('domain_id', sql.String(length=64), primary_key=True),
sql.Column('data', ks_sql.JsonBlob.impl),
mysql_engine='InnoDB',
mysql_charset='utf8')
user_group_membership = sql.Table(
'user_group_membership', meta,
sql.Column('user_id', sql.String(length=64), primary_key=True),
sql.Column('group_id', sql.String(length=64), primary_key=True),
mysql_engine='InnoDB',
mysql_charset='utf8')
user_project_metadata = sql.Table(
'user_project_metadata', meta,
sql.Column('user_id', sql.String(length=64), primary_key=True),
sql.Column('project_id', sql.String(length=64), primary_key=True),
sql.Column('data', ks_sql.JsonBlob.impl),
mysql_engine='InnoDB',
mysql_charset='utf8')
# create all tables
tables = [credential, domain, endpoint, group, group_domain_metadata,
group_project_metadata, policy, project, role, service,
token, trust, trust_role, user, user_domain_metadata,
user_group_membership, user_project_metadata]
for table in tables:
try:
table.create()
except Exception:
LOG.exception('Exception while creating table: %r', table)
raise
# Unique Constraints
migrate.UniqueConstraint(user.c.domain_id,
user.c.name,
name='ixu_user_name_domain_id').create()
migrate.UniqueConstraint(group.c.domain_id,
group.c.name,
name='ixu_group_name_domain_id').create()
migrate.UniqueConstraint(role.c.name,
name='ixu_role_name').create()
migrate.UniqueConstraint(project.c.domain_id,
project.c.name,
name='ixu_project_name_domain_id').create()
migrate.UniqueConstraint(domain.c.name,
name='ixu_domain_name').create()
# Indexes
sql.Index('ix_token_expires', token.c.expires).create()
sql.Index('ix_token_expires_valid', token.c.expires,
token.c.valid).create()
fkeys = [
{'columns': [user_project_metadata.c.project_id],
'references': [project.c.id],
'name': 'fk_user_project_metadata_project_id'},
{'columns': [user_domain_metadata.c.domain_id],
'references': [domain.c.id],
'name': 'fk_user_domain_metadata_domain_id'},
{'columns': [group_project_metadata.c.project_id],
'references': [project.c.id],
'name': 'fk_group_project_metadata_project_id'},
{'columns': [group_domain_metadata.c.domain_id],
'references': [domain.c.id],
'name': 'fk_group_domain_metadata_domain_id'},
{'columns': [endpoint.c.service_id],
'references': [service.c.id]},
{'columns': [user_group_membership.c.group_id],
'references': [group.c.id],
'name': 'fk_user_group_membership_group_id'},
{'columns': [user_group_membership.c.user_id],
'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'}
]
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-Havana release db schema is '
'unsupported.')
@@ -1,31 +0,0 @@
# Copyright 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.
import sqlalchemy as sql
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
token = sql.Table('token', meta, autoload=True)
idx = sql.Index('ix_token_valid', token.c.valid)
idx.drop(migrate_engine)
def downgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
token = sql.Table('token', meta, autoload=True)
idx = sql.Index('ix_token_valid', token.c.valid)
idx.create(migrate_engine)
+22 -1
View File
@@ -22,11 +22,29 @@ from migrate import exceptions
import sqlalchemy
from keystone.common import sql
from keystone import config
from keystone import contrib
from keystone import exception
from keystone.openstack.common.db.sqlalchemy import migration
from keystone.openstack.common.gettextutils import _
from keystone.openstack.common import importutils
from keystone.openstack.common import jsonutils
DB_INIT_VERSION = 35
CONF = config.CONF
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.'})}
# Different RDBMSs use different schemes for naming the Foreign Key
@@ -117,7 +135,9 @@ def find_migrate_repo(package=None, repo_name='migrate_repo'):
def sync_database_to_version(extension=None, version=None):
if not extension:
abs_path = find_migrate_repo()
init_version = DB_INIT_VERSION
else:
init_version = 0
try:
package_name = '.'.join((contrib.__name__, extension))
package = importutils.import_module(package_name)
@@ -136,7 +156,8 @@ def sync_database_to_version(extension=None, version=None):
except exception.MigrationNotProvided as e:
print(e)
sys.exit(1)
migration.db_sync(sql.get_engine(), abs_path, version=version)
migration.db_sync(sql.get_engine(), abs_path, version=version,
init_version=init_version)
def get_db_version(extension=None):
File diff suppressed because it is too large Load Diff