diff --git a/nova/block_device.py b/nova/block_device.py index e67f013c54..c3a3cc3624 100644 --- a/nova/block_device.py +++ b/nova/block_device.py @@ -48,7 +48,7 @@ bdm_new_fields = set(['source_type', 'destination_type', 'connection_info', 'tag']) -bdm_db_only_fields = set(['id', 'instance_uuid']) +bdm_db_only_fields = set(['id', 'instance_uuid', 'attachment_id']) bdm_db_inherited_fields = set(['created_at', 'updated_at', diff --git a/nova/db/sqlalchemy/migrate_repo/versions/358_bdm_attachment_id.py b/nova/db/sqlalchemy/migrate_repo/versions/358_bdm_attachment_id.py new file mode 100644 index 0000000000..da0f465838 --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/358_bdm_attachment_id.py @@ -0,0 +1,28 @@ +# 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 +from sqlalchemy import MetaData +from sqlalchemy import String +from sqlalchemy import Table + + +def upgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + for prefix in ('', 'shadow_'): + table = Table(prefix + 'block_device_mapping', meta, autoload=True) + new_column = Column('attachment_id', String(36), nullable=True) + if not hasattr(table.c, 'attachment_id'): + table.create_column(new_column) diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 90b63a9b76..776b2fdf15 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -623,6 +623,8 @@ class BlockDeviceMapping(BASE, NovaBase, models.SoftDeleteMixin): tag = Column(String(255)) + attachment_id = Column(String(36)) + class SecurityGroupInstanceAssociation(BASE, NovaBase, models.SoftDeleteMixin): __tablename__ = 'security_group_instance_association' diff --git a/nova/tests/unit/db/test_db_api.py b/nova/tests/unit/db/test_db_api.py index 2d6206549e..2f05c055bf 100644 --- a/nova/tests/unit/db/test_db_api.py +++ b/nova/tests/unit/db/test_db_api.py @@ -6360,14 +6360,22 @@ class BlockDeviceMappingTestCase(test.TestCase): bdm = self._create_bdm({}) self.assertIsNotNone(bdm) + def test_block_device_mapping_create_with_attachment_id(self): + bdm = self._create_bdm({'attachment_id': uuidsentinel.attachment_id}) + self.assertEqual(uuidsentinel.attachment_id, bdm.attachment_id) + def test_block_device_mapping_update(self): bdm = self._create_bdm({}) + self.assertIsNone(bdm.attachment_id) result = db.block_device_mapping_update( - self.ctxt, bdm['id'], {'destination_type': 'moon'}, - legacy=False) + self.ctxt, bdm['id'], + {'destination_type': 'moon', + 'attachment_id': uuidsentinel.attachment_id}, + legacy=False) uuid = bdm['instance_uuid'] bdm_real = db.block_device_mapping_get_all_by_instance(self.ctxt, uuid) self.assertEqual(bdm_real[0]['destination_type'], 'moon') + self.assertEqual(uuidsentinel.attachment_id, bdm_real[0].attachment_id) # Also make sure the update call returned correct data self.assertEqual(dict(bdm_real[0]), dict(result)) diff --git a/nova/tests/unit/db/test_migrations.py b/nova/tests/unit/db/test_migrations.py index 98cbf92666..7270445261 100644 --- a/nova/tests/unit/db/test_migrations.py +++ b/nova/tests/unit/db/test_migrations.py @@ -943,6 +943,10 @@ class NovaMigrationsCheckers(test_migrations.ModelsMigrationsSync, 'instances_updated_at_project_id_idx', ['updated_at', 'project_id']) + def _check_358(self, engine, data): + self.assertColumnExists(engine, 'block_device_mapping', + 'attachment_id') + class TestNovaMigrationsSQLite(NovaMigrationsCheckers, test_base.DbTestCase,