diff --git a/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/022_request_specs_spec_mediumtext.py b/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/022_request_specs_spec_mediumtext.py new file mode 100644 index 000000000000..e0eef79a022c --- /dev/null +++ b/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/022_request_specs_spec_mediumtext.py @@ -0,0 +1,25 @@ +# 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 +from sqlalchemy import Table + +from nova.db.sqlalchemy import api_models + + +def upgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + request_specs = Table('request_specs', meta, autoload=True) + if request_specs.c.spec.type != api_models.MediumText(): + request_specs.c.spec.alter(type=api_models.MediumText()) diff --git a/nova/db/sqlalchemy/api_models.py b/nova/db/sqlalchemy/api_models.py index 27a7842d14d9..0635361563a4 100644 --- a/nova/db/sqlalchemy/api_models.py +++ b/nova/db/sqlalchemy/api_models.py @@ -167,7 +167,7 @@ class RequestSpec(API_BASE): id = Column(Integer, primary_key=True) instance_uuid = Column(String(36), nullable=False) - spec = Column(Text, nullable=False) + spec = Column(MediumText(), nullable=False) class Flavors(API_BASE): diff --git a/nova/tests/functional/db/api/test_migrations.py b/nova/tests/functional/db/api/test_migrations.py index f8fac838c54e..865aa4574af9 100644 --- a/nova/tests/functional/db/api/test_migrations.py +++ b/nova/tests/functional/db/api/test_migrations.py @@ -36,6 +36,7 @@ import mock from oslo_db.sqlalchemy import test_base from oslo_db.sqlalchemy import test_migrations from oslo_db.sqlalchemy import utils as db_utils +from oslo_serialization import jsonutils import sqlalchemy from sqlalchemy.engine import reflection @@ -480,6 +481,36 @@ class NovaAPIMigrationsWalk(test_migrations.WalkVersionsMixin): self.assertEqual('{"uuid": "foo", "name": "bar"}', fake_build_req.instance) + def _pre_upgrade_022(self, engine): + request_specs = db_utils.get_table(engine, 'request_specs') + # The spec value is a serialized json blob. + spec = jsonutils.dumps( + {"instance_group": {"id": 42, + "members": ["uuid1", + "uuid2", + "uuid3"]}}) + fake_request_spec = { + 'id': 42, 'spec': spec, + 'instance_uuid': 'c65539ad-b7f5-43d8-934a-018d42424da8'} + request_specs.insert().execute(fake_request_spec) + + def _check_022(self, engine, data): + request_specs = db_utils.get_table(engine, 'request_specs') + if engine.name == 'mysql': + self.assertIsInstance(request_specs.c.spec.type, + sqlalchemy.dialects.mysql.MEDIUMTEXT) + + expected_spec = {"instance_group": {"id": 42, + "members": ["uuid1", + "uuid2", + "uuid3"]}} + from_db_request_spec = request_specs.select( + request_specs.c.id == 42).execute().first() + self.assertEqual('c65539ad-b7f5-43d8-934a-018d42424da8', + from_db_request_spec['instance_uuid']) + db_spec = jsonutils.loads(from_db_request_spec['spec']) + self.assertDictEqual(expected_spec, db_spec) + class TestNovaAPIMigrationsWalkSQLite(NovaAPIMigrationsWalk, test_base.DbTestCase, diff --git a/releasenotes/notes/bug-1738094-request_specs.spec-migration-22d3421ea1536a37.yaml b/releasenotes/notes/bug-1738094-request_specs.spec-migration-22d3421ea1536a37.yaml new file mode 100644 index 000000000000..c333cc93e748 --- /dev/null +++ b/releasenotes/notes/bug-1738094-request_specs.spec-migration-22d3421ea1536a37.yaml @@ -0,0 +1,11 @@ +--- +upgrade: + - | + This release contains a schema migration for the ``nova_api`` database + in order to address bug 1738094: + + https://bugs.launchpad.net/nova/+bug/1738094 + + The migration is optional and can be postponed if you have not been + affected by the bug. The bug manifests itself through "Data too long for + column 'spec'" database errors.