summaryrefslogtreecommitdiffstats
path: root/nova/db
diff options
context:
space:
mode:
authorJohn Griffith <john.griffith@solidfire.com>2012-04-12 20:36:48 -0600
committerJohn Griffith <john.griffith@solidfire.com>2012-05-02 13:32:19 -0600
commit407e16b863bac1dfbf4e954837009abf9c17f018 (patch)
tree10af13810b6746c0fad249b42d3f71466ca87428 /nova/db
parentca2bb061a728bb5db8781f298c18c980d9d91863 (diff)
Convert Volume and Snapshot IDs to use UUID
* Three migrations 1. create id mappings 2. convert volume_id and snapshot_id from int to string 3. change volume/snapshot id's from int to uuid * DB migration for Volume and Related tables * Addition of new volume id mapping tables * Added methods in ec2utils * Minor tweaks to unit tests * Other changes to migration to ensure consistency in id's * Fixed bug in the block-device-mapping table (wasn't setting autoinc) Change-Id: Ic6c3646e0f01c26467a4a3c20e13eebaa2baa97e
Diffstat (limited to 'nova/db')
-rw-r--r--nova/db/api.py23
-rw-r--r--nova/db/sqlalchemy/api.py102
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/089_add_volume_id_mappings.py116
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/090_modify_volume_id_datatype.py236
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/090_sqlite_downgrade.sql226
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/090_sqlite_upgrade.sql226
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/091_convert_volume_ids_to_uuid.py145
-rw-r--r--nova/db/sqlalchemy/models.py35
8 files changed, 1098 insertions, 11 deletions
diff --git a/nova/db/api.py b/nova/db/api.py
index 5de921667..d6eb43146 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -60,10 +60,10 @@ db_opts = [
default='instance-%08x',
help='Template string to be used to generate instance names'),
cfg.StrOpt('volume_name_template',
- default='volume-%08x',
+ default='volume-%s',
help='Template string to be used to generate instance names'),
cfg.StrOpt('snapshot_name_template',
- default='snapshot-%08x',
+ default='snapshot-%s',
help='Template string to be used to generate snapshot names'),
]
@@ -1025,6 +1025,25 @@ def volume_update(context, volume_id, values):
return IMPL.volume_update(context, volume_id, values)
+def get_ec2_volume_id_by_uuid(context, volume_id):
+ return IMPL.get_ec2_volume_id_by_uuid(context, volume_id)
+
+
+def get_volume_uuid_by_ec2_id(context, ec2_id):
+ return IMPL.get_volume_uuid_by_ec2_id(context, ec2_id)
+
+
+def ec2_volume_create(context, volume_id, forced_id=None):
+ return IMPL.ec2_volume_create(context, volume_id, forced_id)
+
+
+def get_snapshot_uuid_by_ec2_id(context, ec2_id):
+ return IMPL.get_snapshot_uuid_by_ec2_id(context, ec2_id)
+
+
+def get_ec2_snapshot_id_by_uuid(context, snapshot_id):
+ return IMPL.get_ec2_snapshot_id_by_uuid(context, snapshot_id)
+
####################
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 1d7509aef..15a843306 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -2171,6 +2171,7 @@ def iscsi_target_count_by_host(context, host):
@require_admin_context
def iscsi_target_create_safe(context, values):
iscsi_target_ref = models.IscsiTarget()
+
for (key, value) in values.iteritems():
iscsi_target_ref[key] = value
try:
@@ -2409,11 +2410,15 @@ def volume_create(context, values):
values['volume_metadata'] = _metadata_refs(values.get('metadata'),
models.VolumeMetadata)
volume_ref = models.Volume()
+ if not values.get('id'):
+ values['id'] = str(utils.gen_uuid())
volume_ref.update(values)
session = get_session()
with session.begin():
volume_ref.save(session=session)
+
+ ec2_volume_create(context, volume_ref['id'])
return volume_ref
@@ -2471,6 +2476,18 @@ def _volume_get_query(context, session=None, project_only=False):
@require_context
+def _ec2_volume_get_query(context, session=None, project_only=False):
+ return model_query(context, models.VolumeIdMapping, session=session,
+ project_only=project_only)
+
+
+@require_context
+def _ec2_snapshot_get_query(context, session=None, project_only=False):
+ return model_query(context, models.SnapshotIdMapping, session=session,
+ project_only=project_only)
+
+
+@require_context
def volume_get(context, volume_id, session=None):
result = _volume_get_query(context, session=session, project_only=True).\
filter_by(id=volume_id).\
@@ -2549,6 +2566,88 @@ def volume_update(context, volume_id, values):
volume_ref.save(session=session)
+@require_context
+def ec2_volume_create(context, volume_uuid, id=None):
+ """Create ec2 compatable volume by provided uuid"""
+ ec2_volume_ref = models.VolumeIdMapping()
+ ec2_volume_ref.update({'uuid': volume_uuid})
+ if id is not None:
+ ec2_volume_ref.update({'id': id})
+
+ ec2_volume_ref.save()
+
+ return ec2_volume_ref
+
+
+@require_context
+def get_ec2_volume_id_by_uuid(context, volume_id, session=None):
+ result = _ec2_volume_get_query(context,
+ session=session,
+ project_only=True).\
+ filter_by(uuid=volume_id).\
+ first()
+
+ if not result:
+ raise exception.VolumeNotFound(uuid=volume_id)
+
+ return result['id']
+
+
+@require_context
+def get_volume_uuid_by_ec2_id(context, ec2_id, session=None):
+ result = _ec2_volume_get_query(context,
+ session=session,
+ project_only=True).\
+ filter_by(id=ec2_id).\
+ first()
+
+ if not result:
+ raise exception.VolumeNotFound(ec2_id=ec2_id)
+
+ return result['uuid']
+
+
+@require_context
+def ec2_snapshot_create(context, snapshot_uuid, id=None):
+ """Create ec2 compatable snapshot by provided uuid"""
+ ec2_snapshot_ref = models.SnapshotIdMapping()
+ ec2_snapshot_ref.update({'uuid': snapshot_uuid})
+ if id is not None:
+ ec2_snapshot_ref.update({'id': id})
+
+ ec2_snapshot_ref.save()
+
+ return ec2_snapshot_ref
+
+
+@require_context
+def get_ec2_snapshot_id_by_uuid(context, snapshot_id, session=None):
+ result = _ec2_snapshot_get_query(context,
+ session=session,
+ project_only=True).\
+ filter_by(uuid=snapshot_id).\
+ first()
+
+ if not result:
+ raise exception.SnapshotNotFound(uuid=snapshot_id)
+
+ return result['id']
+
+
+@require_context
+def get_snapshot_uuid_by_ec2_id(context, ec2_id, session=None):
+ result = _ec2_snapshot_get_query(context,
+ session=session,
+ project_only=True).\
+ filter_by(id=ec2_id).\
+ first()
+
+ if not result:
+ raise exception.SnapshotNotFound(ec2_id=ec2_id)
+
+ return result['uuid']
+
+
####################
def _volume_metadata_get_query(context, volume_id, session=None):
@@ -2633,11 +2732,14 @@ def volume_metadata_update(context, volume_id, metadata, delete):
@require_context
def snapshot_create(context, values):
snapshot_ref = models.Snapshot()
+ if not values.get('id'):
+ values['id'] = str(utils.gen_uuid())
snapshot_ref.update(values)
session = get_session()
with session.begin():
snapshot_ref.save(session=session)
+ ec2_snapshot_create(context, snapshot_ref['id'])
return snapshot_ref
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/089_add_volume_id_mappings.py b/nova/db/sqlalchemy/migrate_repo/versions/089_add_volume_id_mappings.py
new file mode 100644
index 000000000..d3a705abc
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/089_add_volume_id_mappings.py
@@ -0,0 +1,116 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from sqlalchemy import Boolean, Column, DateTime, Integer
+from sqlalchemy import MetaData, String, Table
+from nova import log as logging
+from nova import utils
+
+LOG = logging.getLogger(__name__)
+
+
+def upgrade(migrate_engine):
+ """Build mapping tables for our volume uuid migration.
+
+ These mapping tables serve two purposes:
+ 1. Provide a method for downgrade after UUID conversion
+ 2. Provide a uuid to associate with existing volumes and snapshots
+ when we do the actual datatype migration from int to uuid
+
+ """
+ meta = MetaData()
+ meta.bind = migrate_engine
+
+ volume_id_mappings = Table('volume_id_mappings', meta,
+ Column('created_at',
+ DateTime(timezone=False)),
+ Column('updated_at',
+ DateTime(timezone=False)),
+ Column('deleted_at',
+ DateTime(timezone=False)),
+ Column('deleted',
+ Boolean(create_constraint=True, name=None)),
+ Column('id', Integer(),
+ primary_key=True,
+ nullable=False,
+ autoincrement=True),
+ Column('uuid', String(36),
+ nullable=False))
+ try:
+ volume_id_mappings.create()
+ except Exception:
+ LOG.exception("Exception while creating table 'volume_id_mappings'")
+ meta.drop_all(tables=[volume_id_mappings])
+ raise
+
+ snapshot_id_mappings = Table('snapshot_id_mappings', meta,
+ Column('created_at',
+ DateTime(timezone=False)),
+ Column('updated_at',
+ DateTime(timezone=False)),
+ Column('deleted_at',
+ DateTime(timezone=False)),
+ Column('deleted',
+ Boolean(create_constraint=True, name=None)),
+ Column('id', Integer(),
+ primary_key=True,
+ nullable=False,
+ autoincrement=True),
+ Column('uuid', String(36),
+ nullable=False))
+ try:
+ snapshot_id_mappings.create()
+ except Exception:
+ LOG.exception("Exception while creating table 'snapshot_id_mappings'")
+ meta.drop_all(tables=[snapshot_id_mappings])
+ raise
+
+ if migrate_engine.name == "mysql":
+ migrate_engine.execute("ALTER TABLE volume_id_mappings Engine=InnoDB")
+ migrate_engine.execute("ALTER TABLE snapshot_id_mappings "\
+ "Engine=InnoDB")
+
+ volumes = Table('volumes', meta, autoload=True)
+ snapshots = Table('snapshots', meta, autoload=True)
+ volume_id_mappings = Table('volume_id_mappings', meta, autoload=True)
+ snapshot_id_mappings = Table('snapshot_id_mappings', meta, autoload=True)
+
+ volume_list = list(volumes.select().execute())
+ for v in volume_list:
+ old_id = v['id']
+ new_id = utils.gen_uuid()
+ row = volume_id_mappings.insert()
+ row.execute({'id': old_id,
+ 'uuid': str(new_id)})
+
+ snapshot_list = list(snapshots.select().execute())
+ for s in snapshot_list:
+ old_id = s['id']
+ new_id = utils.gen_uuid()
+ row = snapshot_id_mappings.insert()
+ row.execute({'id': old_id,
+ 'uuid': str(new_id)})
+
+
+def downgrade(migrate_engine):
+ meta = MetaData()
+ meta.bind = migrate_engine
+ volume_id_mappings = Table('volume_id_mappings', meta, autoload=True)
+ volume_id_mappings.drop()
+
+ snapshot_id_mappings = Table('snapshot_id_mappings', meta, autoload=True)
+ snapshot_id_mappings.drop()
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/090_modify_volume_id_datatype.py b/nova/db/sqlalchemy/migrate_repo/versions/090_modify_volume_id_datatype.py
new file mode 100644
index 000000000..36a6ba200
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/090_modify_volume_id_datatype.py
@@ -0,0 +1,236 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from sqlalchemy import Integer
+from sqlalchemy import MetaData, String, Table
+from migrate import ForeignKeyConstraint
+from nova import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+def upgrade(migrate_engine):
+ """Convert volume and snapshot id columns from int to varchar."""
+ meta = MetaData()
+ meta.bind = migrate_engine
+ dialect = migrate_engine.url.get_dialect().name
+
+ volumes = Table('volumes', meta, autoload=True)
+ snapshots = Table('snapshots', meta, autoload=True)
+ iscsi_targets = Table('iscsi_targets', meta, autoload=True)
+ volume_metadata = Table('volume_metadata', meta, autoload=True)
+ sm_volume = Table('sm_volume', meta, autoload=True)
+ block_device_mapping = Table('block_device_mapping', meta, autoload=True)
+
+ try:
+ fkeys = list(snapshots.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[snapshots.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).drop()
+
+ fkeys = list(iscsi_targets.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[iscsi_targets.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).drop()
+
+ fkeys = list(volume_metadata.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[volume_metadata.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).drop()
+
+ fkeys = list(sm_volume.c.id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[sm_volume.c.id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).drop()
+
+ fkeys = list(block_device_mapping.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[block_device_mapping.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).drop()
+
+ fkeys = list(block_device_mapping.c.snapshot_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[block_device_mapping.c.snapshot_id],
+ refcolumns=[snapshots.c.id],
+ name=fkey_name).drop()
+
+ except Exception:
+ LOG.error(_("Foreign Key constraint couldn't be removed"))
+ raise
+
+ volumes.c.id.alter(String(36), primary_key=True)
+ volumes.c.snapshot_id.alter(String(36))
+ volume_metadata.c.volume_id.alter(String(36), nullable=False)
+ snapshots.c.id.alter(String(36), primary_key=True)
+ snapshots.c.volume_id.alter(String(36))
+ sm_volume.c.id.alter(String(36))
+ block_device_mapping.c.volume_id.alter(String(36))
+ block_device_mapping.c.snapshot_id.alter(String(36))
+ iscsi_targets.c.volume_id.alter(String(36), nullable=True)
+
+ try:
+ fkeys = list(snapshots.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[snapshots.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).create()
+
+ fkeys = list(iscsi_targets.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[iscsi_targets.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).create()
+
+ fkeys = list(volume_metadata.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[volume_metadata.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).create()
+
+ fkeys = list(sm_volume.c.id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[sm_volume.c.id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).create()
+ # NOTE(jdg) We're intentionally leaving off FK's on BDM
+
+ except Exception:
+ LOG.error(_("Foreign Key constraint couldn't be removed"))
+ raise
+
+
+def downgrade(migrate_engine):
+ """Convert volume and snapshot id columns back to int."""
+ meta = MetaData()
+ meta.bind = migrate_engine
+ dialect = migrate_engine.url.get_dialect().name
+
+ if dialect.startswith('sqlite'):
+ return
+
+ volumes = Table('volumes', meta, autoload=True)
+ snapshots = Table('snapshots', meta, autoload=True)
+ iscsi_targets = Table('iscsi_targets', meta, autoload=True)
+ volume_metadata = Table('volume_metadata', meta, autoload=True)
+ sm_volume = Table('sm_volume', meta, autoload=True)
+ block_device_mapping = Table('block_device_mapping', meta, autoload=True)
+
+ try:
+ fkeys = list(snapshots.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[snapshots.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).drop()
+
+ fkeys = list(iscsi_targets.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[iscsi_targets.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).drop()
+
+ fkeys = list(volume_metadata.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[volume_metadata.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).drop()
+
+ fkeys = list(sm_volume.c.id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[sm_volume.c.id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).drop()
+
+ except Exception:
+ LOG.error(_("Foreign Key constraint couldn't be removed"))
+ raise
+
+ volumes.c.id.alter(Integer, primary_key=True, autoincrement=True)
+ volumes.c.snapshot_id.alter(Integer)
+ volume_metadata.c.volume_id.alter(Integer, nullable=False)
+ snapshots.c.id.alter(Integer, primary_key=True, autoincrement=True)
+ snapshots.c.volume_id.alter(Integer)
+ sm_volume.c.id.alter(Integer)
+ block_device_mapping.c.volume_id.alter(Integer)
+ block_device_mapping.c.snapshot_id.alter(Integer)
+ iscsi_targets.c.volume_id.alter(Integer, nullable=True)
+
+ try:
+ fkeys = list(snapshots.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[snapshots.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).create()
+
+ fkeys = list(iscsi_targets.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[iscsi_targets.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).create()
+
+ fkeys = list(volume_metadata.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[volume_metadata.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).create()
+
+ fkeys = list(sm_volume.c.id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[sm_volume.c.id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).create()
+
+ # NOTE(jdg) Put the BDM foreign keys back in place
+ fkeys = list(block_device_mapping.c.volume_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[block_device_mapping.c.volume_id],
+ refcolumns=[volumes.c.id],
+ name=fkey_name).drop()
+
+ fkeys = list(block_device_mapping.c.snapshot_id.foreign_keys)
+ if fkeys:
+ fkey_name = fkeys[0].constraint.name
+ ForeignKeyConstraint(columns=[block_device_mapping.c.snapshot_id],
+ refcolumns=[snapshots.c.id],
+ name=fkey_name).drop()
+
+ except Exception:
+ LOG.error(_("Foreign Key constraint couldn't be removed"))
+ raise
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/090_sqlite_downgrade.sql b/nova/db/sqlalchemy/migrate_repo/versions/090_sqlite_downgrade.sql
new file mode 100644
index 000000000..7d89da247
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/090_sqlite_downgrade.sql
@@ -0,0 +1,226 @@
+BEGIN TRANSACTION;
+
+ -- change id and snapshot_id datatypes in volumes table
+ CREATE TABLE volumes_backup(
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ ec2_id INTEGER,
+ user_id VARCHAR(255),
+ project_id VARCHAR(255),
+ snapshot_id VARCHAR(255),
+ host VARCHAR(255),
+ size INTEGER,
+ availability_zone VARCHAR(255),
+ instance_id INTEGER,
+ mountpoint VARCHAR(255),
+ attach_time VARCHAR(255),
+ status VARCHAR(255),
+ attach_status VARCHAR(255),
+ scheduled_at DATETIME,
+ launched_at DATETIME,
+ terminated_at DATETIME,
+ display_name VARCHAR(255),
+ display_description VARCHAR(255),
+ provider_location VARCHAR(255),
+ provider_auth VARCHAR(255),
+ volume_type_id INTEGER,
+ PRIMARY KEY (id),
+ FOREIGN KEY(instance_id) REFERENCES instances (id),
+ UNIQUE (id),
+ CHECK (deleted IN (0, 1))
+ );
+
+ INSERT INTO volumes_backup SELECT
+ created_at,
+ updated_at,
+ deleted_at,
+ deleted,
+ id,
+ ec2_id,
+ user_id,
+ project_id,
+ snapshot_id,
+ host,
+ size,
+ availability_zone,
+ instance_id,
+ mountpoint,
+ attach_time,
+ status,
+ attach_status,
+ scheduled_at,
+ launched_at,
+ terminated_at,
+ display_name,
+ display_description,
+ provider_location,
+ provider_auth,
+ volume_type_id
+ FROM volumes;
+ DROP TABLE volumes;
+ ALTER TABLE volumes_backup RENAME TO volumes;
+
+ -- change id and volume_id datatypes in snapshots table
+ CREATE TABLE snapshots_backup (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ user_id VARCHAR(255),
+ project_id VARCHAR(255),
+ volume_id INTEGER,
+ status VARCHAR(255),
+ progress VARCHAR(255),
+ volume_size INTEGER,
+ display_name VARCHAR(255),
+ display_description VARCHAR(255),
+ PRIMARY KEY (id),
+ UNIQUE (id),
+ CHECK (deleted IN (0, 1))
+ );
+ INSERT INTO snapshots_backup SELECT
+ created_at,
+ updated_at,
+ deleted_at,
+ deleted,
+ id,
+ user_id,
+ project_id,
+ volume_id,
+ status,
+ progress,
+ volume_size,
+ display_name,
+ display_description
+ FROM snapshots;
+ DROP TABLE snapshots;
+ ALTER TABLE snapshots_backup RENAME TO snapshots;
+
+ -- change id and volume_id datatypes in iscsi_targets table
+ CREATE TABLE iscsi_targets_backup (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ target_num INTEGER,
+ host VARCHAR(255),
+ volume_id INTEGER,
+ PRIMARY KEY (id),
+ FOREIGN KEY(volume_id) REFERENCES volumes(id),
+ UNIQUE (id),
+ CHECK (deleted IN (0, 1))
+ );
+ INSERT INTO iscsi_targets_backup SELECT
+ created_at,
+ updated_at,
+ deleted_at,
+ deleted,
+ id,
+ target_num,
+ host,
+ volume_id
+ FROM iscsi_targets;
+ DROP TABLE iscsi_targets;
+ ALTER TABLE iscsi_targets_backup RENAME TO iscsi_targets;
+
+ CREATE TABLE volume_metadata_backup (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ key VARCHAR(255),
+ value VARCHAR(255),
+ volume_id INTEGER,
+ PRIMARY KEY (id),
+ FOREIGN KEY(volume_id) REFERENCES volumes(id),
+ UNIQUE (id),
+ CHECK (deleted IN (0, 1))
+ );
+ INSERT INTO volume_metadata_backup SELECT
+ created_at,
+ updated_at,
+ deleted_at,
+ deleted,
+ id,
+ key,
+ value,
+ volume_id
+ FROM volume_metadata;
+ DROP TABLE volume_metadata;
+ ALTER TABLE volume_metadata_backup RENAME TO volume_metadata;
+
+ -- change volume_id and snapshot_id datatypes in bdm table
+ CREATE TABLE block_device_mapping_backup (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ instance_uuid VARCHAR(36) NOT NULL,
+ device_name VARCHAR(255),
+ delete_on_termination BOOLEAN,
+ virtual_name VARCHAR(255),
+ snapshot_id INTEGER,
+ volume_id INTEGER,
+ volume_size INTEGER,
+ no_device BOOLEAN,
+ connection_info VARCHAR(255),
+ FOREIGN KEY(instance_uuid) REFERENCES instances(id),
+ FOREIGN KEY(volume_id) REFERENCES volumes(id),
+ FOREIGN KEY(snapshot_id) REFERENCES snapshots(id),
+ PRIMARY KEY (id),
+ UNIQUE (id),
+ CHECK (deleted IN (0, 1))
+ );
+ INSERT INTO block_device_mapping_backup SELECT
+ created_at,
+ updated_at,
+ deleted_at,
+ deleted,
+ id,
+ instance_uuid,
+ device_name,
+ delete_on_termination,
+ virtual_name,
+ snapshot_id,
+ volume_id,
+ volume_size,
+ no_device,
+ connection_info
+ FROM block_device_mapping;
+ DROP TABLE block_device_mapping;
+ ALTER TABLE block_device_mapping_backup RENAME TO block_device_mapping;
+
+ -- change volume_id and sm_volume_table
+ CREATE TABLE sm_volume_backup (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ backend_id INTEGER NOT NULL,
+ vdi_uuid VARCHAR(255),
+ PRIMARY KEY (id),
+ FOREIGN KEY(id) REFERENCES volumes(id),
+ UNIQUE (id),
+ CHECK (deleted IN (0,1))
+ );
+ INSERT INTO sm_volume_backup SELECT
+ created_at,
+ updated_at,
+ deleted_at,
+ deleted,
+ id,
+ backend_id,
+ vdi_uuid
+ FROM sm_volume;
+ DROP TABLE sm_volume;
+ ALTER TABLE sm_volume_backup RENAME TO sm_volume;
+
+COMMIT;
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/090_sqlite_upgrade.sql b/nova/db/sqlalchemy/migrate_repo/versions/090_sqlite_upgrade.sql
new file mode 100644
index 000000000..53fbc69f6
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/090_sqlite_upgrade.sql
@@ -0,0 +1,226 @@
+BEGIN TRANSACTION;
+
+ -- change id and snapshot_id datatypes in volumes table
+ CREATE TABLE volumes_backup(
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id VARCHAR(36) NOT NULL,
+ ec2_id INTEGER,
+ user_id VARCHAR(255),
+ project_id VARCHAR(255),
+ snapshot_id VARCHAR(36),
+ host VARCHAR(255),
+ size INTEGER,
+ availability_zone VARCHAR(255),
+ instance_id INTEGER,
+ mountpoint VARCHAR(255),
+ attach_time VARCHAR(255),
+ status VARCHAR(255),
+ attach_status VARCHAR(255),
+ scheduled_at DATETIME,
+ launched_at DATETIME,
+ terminated_at DATETIME,
+ display_name VARCHAR(255),
+ display_description VARCHAR(255),
+ provider_location VARCHAR(255),
+ provider_auth VARCHAR(255),
+ volume_type_id INTEGER,
+ PRIMARY KEY (id),
+ FOREIGN KEY(instance_id) REFERENCES instances (id),
+ UNIQUE (id),
+ CHECK (deleted IN (0, 1))
+ );
+
+ INSERT INTO volumes_backup SELECT
+ created_at,
+ updated_at,
+ deleted_at,
+ deleted,
+ id,
+ ec2_id,
+ user_id,
+ project_id,
+ snapshot_id,
+ host,
+ size,
+ availability_zone,
+ instance_id,
+ mountpoint,
+ attach_time,
+ status,
+ attach_status,
+ scheduled_at,
+ launched_at,
+ terminated_at,
+ display_name,
+ display_description,
+ provider_location,
+ provider_auth,
+ volume_type_id
+ FROM volumes;
+ DROP TABLE volumes;
+ ALTER TABLE volumes_backup RENAME TO volumes;
+
+ -- change id and volume_id datatypes in snapshots table
+ CREATE TABLE snapshots_backup (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id VARCHAR(36) NOT NULL,
+ user_id VARCHAR(255),
+ project_id VARCHAR(255),
+ volume_id VARCHAR(36),
+ status VARCHAR(255),
+ progress VARCHAR(255),
+ volume_size INTEGER,
+ display_name VARCHAR(255),
+ display_description VARCHAR(255),
+ PRIMARY KEY (id),
+ UNIQUE (id),
+ CHECK (deleted IN (0, 1))
+ );
+ INSERT INTO snapshots_backup SELECT
+ created_at,
+ updated_at,
+ deleted_at,
+ deleted,
+ id,
+ user_id,
+ project_id,
+ volume_id,
+ status,
+ progress,
+ volume_size,
+ display_name,
+ display_description
+ FROM snapshots;
+ DROP TABLE snapshots;
+ ALTER TABLE snapshots_backup RENAME TO snapshots;
+
+ -- change id and volume_id datatypes in iscsi_targets table
+ CREATE TABLE iscsi_targets_backup (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ target_num INTEGER,
+ host VARCHAR(255),
+ volume_id VARCHAR(36),
+ PRIMARY KEY (id),
+ FOREIGN KEY(volume_id) REFERENCES volumes(id),
+ UNIQUE (id),
+ CHECK (deleted IN (0, 1))
+ );
+ INSERT INTO iscsi_targets_backup SELECT
+ created_at,
+ updated_at,
+ deleted_at,
+ deleted,
+ id,
+ target_num,
+ host,
+ volume_id
+ FROM iscsi_targets;
+ DROP TABLE iscsi_targets;
+ ALTER TABLE iscsi_targets_backup RENAME TO iscsi_targets;
+
+ CREATE TABLE volume_metadata_backup (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ key VARCHAR(255),
+ value VARCHAR(255),
+ volume_id VARCHAR(36),
+ PRIMARY KEY (id),
+ FOREIGN KEY(volume_id) REFERENCES volumes(id),
+ UNIQUE (id),
+ CHECK (deleted IN (0, 1))
+ );
+ INSERT INTO volume_metadata_backup SELECT
+ created_at,
+ updated_at,
+ deleted_at,
+ deleted,
+ id,
+ key,
+ value,
+ volume_id
+ FROM volume_metadata;
+ DROP TABLE volume_metadata;
+ ALTER TABLE volume_metadata_backup RENAME TO volume_metadata;
+
+ -- change volume_id and snapshot_id datatypes in bdm table
+ CREATE TABLE block_device_mapping_backup (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id INTEGER NOT NULL,
+ instance_uuid VARCHAR(36) NOT NULL,
+ device_name VARCHAR(255),
+ delete_on_termination BOOLEAN,
+ virtual_name VARCHAR(255),
+ snapshot_id VARCHAR(36),
+ volume_id VARCHAR(36),
+ volume_size INTEGER,
+ no_device BOOLEAN,
+ connection_info VARCHAR(255),
+ FOREIGN KEY(instance_uuid) REFERENCES instances(id),
+ FOREIGN KEY(volume_id) REFERENCES volumes(id),
+ FOREIGN KEY(snapshot_id) REFERENCES snapshots(id),
+ PRIMARY KEY (id),
+ UNIQUE (id),
+ CHECK (deleted IN (0, 1))
+ );
+ INSERT INTO block_device_mapping_backup SELECT
+ created_at,
+ updated_at,
+ deleted_at,
+ deleted,
+ id,
+ instance_uuid,
+ device_name,
+ delete_on_termination,
+ virtual_name,
+ snapshot_id,
+ volume_id,
+ volume_size,
+ no_device,
+ connection_info
+ FROM block_device_mapping;
+ DROP TABLE block_device_mapping;
+ ALTER TABLE block_device_mapping_backup RENAME TO block_device_mapping;
+
+ -- change volume_id and sm_volume_table
+ CREATE TABLE sm_volume_backup (
+ created_at DATETIME,
+ updated_at DATETIME,
+ deleted_at DATETIME,
+ deleted BOOLEAN,
+ id VARCHAR(36) NOT NULL,
+ backend_id INTEGER NOT NULL,
+ vdi_uuid VARCHAR(255),
+ PRIMARY KEY (id),
+ FOREIGN KEY(id) REFERENCES volumes(id),
+ UNIQUE (id),
+ CHECK (deleted IN (0,1))
+ );
+ INSERT INTO sm_volume_backup SELECT
+ created_at,
+ updated_at,
+ deleted_at,
+ deleted,
+ id,
+ backend_id,
+ vdi_uuid
+ FROM sm_volume;
+ DROP TABLE sm_volume;
+ ALTER TABLE sm_volume_backup RENAME TO sm_volume;
+
+COMMIT;
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/091_convert_volume_ids_to_uuid.py b/nova/db/sqlalchemy/migrate_repo/versions/091_convert_volume_ids_to_uuid.py
new file mode 100644
index 000000000..5d0440ffe
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/091_convert_volume_ids_to_uuid.py
@@ -0,0 +1,145 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from sqlalchemy import MetaData, select, Table
+from nova import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+def upgrade(migrate_engine):
+ """Convert volume and snapshot id columns from int to varchar."""
+ meta = MetaData()
+ meta.bind = migrate_engine
+
+ volumes = Table('volumes', meta, autoload=True)
+ snapshots = Table('snapshots', meta, autoload=True)
+ iscsi_targets = Table('iscsi_targets', meta, autoload=True)
+ volume_metadata = Table('volume_metadata', meta, autoload=True)
+ block_device_mapping = Table('block_device_mapping', meta, autoload=True)
+ sm_volumes = Table('sm_volume', meta, autoload=True)
+
+ volume_mappings = Table('volume_id_mappings', meta, autoload=True)
+ snapshot_mappings = Table('snapshot_id_mappings', meta, autoload=True)
+
+ volume_list = list(volumes.select().execute())
+ for v in volume_list:
+ new_id = select([volume_mappings.c.uuid],
+ volume_mappings.c.id == v['id'])
+
+ volumes.update().\
+ where(volumes.c.id == v['id']).\
+ values(id=new_id).execute()
+
+ sm_volumes.update().\
+ where(sm_volumes.c.id == v['id']).\
+ values(id=new_id).execute()
+
+ snapshots.update().\
+ where(snapshots.c.volume_id == v['id']).\
+ values(volume_id=new_id).execute()
+
+ iscsi_targets.update().\
+ where(iscsi_targets.c.volume_id == v['id']).\
+ values(volume_id=new_id).execute()
+
+ volume_metadata.update().\
+ where(volume_metadata.c.volume_id == v['id']).\
+ values(volume_id=new_id).execute()
+
+ block_device_mapping.update().\
+ where(block_device_mapping.c.volume_id == v['id']).\
+ values(volume_id=new_id).execute()
+
+ snapshot_list = list(snapshots.select().execute())
+ for s in snapshot_list:
+ new_id = select([snapshot_mappings.c.uuid],
+ volume_mappings.c.id == s['id'])
+
+ volumes.update().\
+ where(volumes.c.snapshot_id == s['id']).\
+ values(snapshot_id=new_id).execute()
+
+ snapshots.update().\
+ where(snapshots.c.id == s['id']).\
+ values(volume_id=new_id).execute()
+
+ block_device_mapping.update().\
+ where(block_device_mapping.c.snapshot_id == s['id']).\
+ values(snapshot_id=new_id).execute()
+
+
+def downgrade(migrate_engine):
+ """Convert volume and snapshot id columns back to int."""
+ meta = MetaData()
+ meta.bind = migrate_engine
+
+ volumes = Table('volumes', meta, autoload=True)
+ snapshots = Table('snapshots', meta, autoload=True)
+ iscsi_targets = Table('iscsi_targets', meta, autoload=True)
+ volume_metadata = Table('volume_metadata', meta, autoload=True)
+ block_device_mapping = Table('block_device_mapping', meta, autoload=True)
+ sm_volumes = Table('sm_volume', meta, autoload=True)
+
+ volume_mappings = Table('volume_id_mappings', meta, autoload=True)
+ snapshot_mappings = Table('snapshot_id_mappings', meta, autoload=True)
+
+ volume_list = list(volumes.select().execute())
+ for v in volume_list:
+ new_id = select([volume_mappings.c.id],
+ volume_mappings.c.uuid == v['id'])
+
+ volumes.update().\
+ where(volumes.c.id == v['id']).\
+ values(id=new_id).execute()
+
+ sm_volumes.update().\
+ where(sm_volumes.c.id == v['id']).\
+ values(id=new_id).execute()
+
+ snapshots.update().\
+ where(snapshots.c.volume_id == v['id']).\
+ values(volume_id=new_id).execute()
+
+ iscsi_targets.update().\
+ where(iscsi_targets.c.volume_id == v['id']).\
+ values(volume_id=new_id).execute()
+
+ volume_metadata.update().\
+ where(volume_metadata.c.volume_id == v['id']).\
+ values(volume_id=new_id).execute()
+
+ block_device_mapping.update().\
+ where(block_device_mapping.c.volume_id == v['id']).\
+ values(volume_id=new_id).execute()
+
+ snapshot_list = list(snapshots.select().execute())
+ for s in snapshot_list:
+ new_id = select([snapshot_mappings.c.id],
+ volume_mappings.c.uuid == s['id'])
+
+ volumes.update().\
+ where(volumes.c.snapshot_id == s['id']).\
+ values(snapshot_id=new_id).execute()
+
+ snapshots.update().\
+ where(snapshots.c.id == s['id']).\
+ values(volume_id=new_id).execute()
+
+ block_device_mapping.update().\
+ where(block_device_mapping.c.snapshot_id == s['id']).\
+ values(snapshot_id=new_id).execute()
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 1544629ff..e4e47c882 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -335,16 +335,17 @@ class InstanceTypes(BASE, NovaBase):
class Volume(BASE, NovaBase):
"""Represents a block storage device that can be attached to a vm."""
__tablename__ = 'volumes'
- id = Column(Integer, primary_key=True, autoincrement=True)
+ id = Column(String(36), primary_key=True)
@property
def name(self):
return FLAGS.volume_name_template % self.id
+ ec2_id = Column(Integer)
user_id = Column(String(255))
project_id = Column(String(255))
- snapshot_id = Column(String(255))
+ snapshot_id = Column(String(36))
host = Column(String(255)) # , ForeignKey('hosts.id'))
size = Column(Integer)
@@ -379,7 +380,7 @@ class VolumeMetadata(BASE, NovaBase):
id = Column(Integer, primary_key=True)
key = Column(String(255))
value = Column(String(255))
- volume_id = Column(Integer, ForeignKey('volumes.id'), nullable=False)
+ volume_id = Column(String(36), ForeignKey('volumes.id'), nullable=False)
volume = relationship(Volume, backref="volume_metadata",
foreign_keys=volume_id,
primaryjoin='and_('
@@ -455,7 +456,7 @@ class QuotaClass(BASE, NovaBase):
class Snapshot(BASE, NovaBase):
"""Represents a block storage device that can be attached to a vm."""
__tablename__ = 'snapshots'
- id = Column(Integer, primary_key=True, autoincrement=True)
+ id = Column(String(36), primary_key=True)
@property
def name(self):
@@ -468,7 +469,7 @@ class Snapshot(BASE, NovaBase):
user_id = Column(String(255))
project_id = Column(String(255))
- volume_id = Column(Integer)
+ volume_id = Column(String(36))
status = Column(String(255))
progress = Column(String(255))
volume_size = Column(Integer)
@@ -504,12 +505,12 @@ class BlockDeviceMapping(BASE, NovaBase):
virtual_name = Column(String(255), nullable=True)
# for snapshot or volume
- snapshot_id = Column(Integer, ForeignKey('snapshots.id'), nullable=True)
+ snapshot_id = Column(String(36), ForeignKey('snapshots.id'))
# outer join
snapshot = relationship(Snapshot,
foreign_keys=snapshot_id)
- volume_id = Column(Integer, ForeignKey('volumes.id'), nullable=True)
+ volume_id = Column(String(36), ForeignKey('volumes.id'), nullable=True)
volume = relationship(Volume,
foreign_keys=volume_id)
volume_size = Column(Integer, nullable=True)
@@ -528,7 +529,7 @@ class IscsiTarget(BASE, NovaBase):
id = Column(Integer, primary_key=True)
target_num = Column(Integer)
host = Column(String(255))
- volume_id = Column(Integer, ForeignKey('volumes.id'), nullable=True)
+ volume_id = Column(String(36), ForeignKey('volumes.id'), nullable=True)
volume = relationship(Volume,
backref=backref('iscsi_target', uselist=False),
foreign_keys=volume_id,
@@ -962,6 +963,20 @@ class S3Image(BASE, NovaBase):
uuid = Column(String(36), nullable=False)
+class VolumeIdMapping(BASE, NovaBase):
+ """Compatability layer for the EC2 volume service"""
+ __tablename__ = 'volume_id_mappings'
+ id = Column(Integer, primary_key=True, nullable=False, autoincrement=True)
+ uuid = Column(String(36), nullable=False)
+
+
+class SnapshotIdMapping(BASE, NovaBase):
+ """Compatability layer for the EC2 snapshot service"""
+ __tablename__ = 'snapshot_id_mappings'
+ id = Column(Integer, primary_key=True, nullable=False, autoincrement=True)
+ uuid = Column(String(36), nullable=False)
+
+
class SMFlavors(BASE, NovaBase):
"""Represents a flavor for SM volumes."""
__tablename__ = 'sm_flavors'
@@ -982,7 +997,7 @@ class SMBackendConf(BASE, NovaBase):
class SMVolume(BASE, NovaBase):
__tablename__ = 'sm_volume'
- id = Column(Integer(), ForeignKey(Volume.id), primary_key=True)
+ id = Column(String(36), ForeignKey(Volume.id), primary_key=True)
backend_id = Column(Integer, ForeignKey('sm_backend_config.id'),
nullable=False)
vdi_uuid = Column(String(255))
@@ -1040,6 +1055,8 @@ def register_models():
VolumeMetadata,
VolumeTypeExtraSpecs,
VolumeTypes,
+ VolumeIdMapping,
+ SnapshotIdMapping,
)
engine = create_engine(FLAGS.sql_connection, echo=False)
for model in models: