From 62afbaeb4441d786a60f067ab1f6eaf71d969640 Mon Sep 17 00:00:00 2001 From: Steve Baker Date: Fri, 28 Feb 2014 15:36:49 +1300 Subject: [PATCH] Change software_config storage of config and io columns Previously the config column was of type LongText and all config scripts were expected to be strings. However there will be many config formats which are best stored and returned as parsed data structures (tripleo metadata, cfn-init, ansible, salt). This change converts the software_config config column to Json and deletes the io column. The config, inputs, outputs and options are now stored in the config Json column as top-level dict entries. No data conversion is needed for this migration since nobody is using software-config in the wild yet. partial blueprint hot-software-config-rest Change-Id: I03dc528bc2a6b255d6baa0eb8b9c1c8a7e6f872c --- .../038_software_config_json_config.py | 34 +++++++++++++++++++ heat/db/sqlalchemy/models.py | 4 +-- heat/engine/api.py | 8 ++--- heat/engine/service.py | 7 ++-- heat/tests/db/test_migrations.py | 3 ++ heat/tests/test_engine_api_utils.py | 6 ++-- heat/tests/test_sqlalchemy_api.py | 16 +++++---- 7 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 heat/db/sqlalchemy/migrate_repo/versions/038_software_config_json_config.py diff --git a/heat/db/sqlalchemy/migrate_repo/versions/038_software_config_json_config.py b/heat/db/sqlalchemy/migrate_repo/versions/038_software_config_json_config.py new file mode 100644 index 0000000000..07408b54b5 --- /dev/null +++ b/heat/db/sqlalchemy/migrate_repo/versions/038_software_config_json_config.py @@ -0,0 +1,34 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# 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 heat.db.sqlalchemy.types import LongText +from heat.db.sqlalchemy.types import Json + +import sqlalchemy + + +def upgrade(migrate_engine): + meta = sqlalchemy.MetaData(bind=migrate_engine) + software_config = sqlalchemy.Table('software_config', meta, autoload=True) + software_config.c.config.alter(type=Json) + software_config.c.io.drop() + + +def downgrade(migrate_engine): + meta = sqlalchemy.MetaData(bind=migrate_engine) + software_config = sqlalchemy.Table('software_config', meta, autoload=True) + software_config.c.config.alter(type=LongText) + + io = sqlalchemy.Column('io', Json) + io.create(software_config) diff --git a/heat/db/sqlalchemy/models.py b/heat/db/sqlalchemy/models.py index 10ee9d16ff..70c814de8f 100644 --- a/heat/db/sqlalchemy/models.py +++ b/heat/db/sqlalchemy/models.py @@ -26,7 +26,6 @@ from heat.openstack.common.db.sqlalchemy import models from heat.openstack.common.db.sqlalchemy import session from sqlalchemy.orm.session import Session from heat.db.sqlalchemy.types import Json -from heat.db.sqlalchemy.types import LongText BASE = declarative_base() get_session = session.get_session @@ -264,8 +263,7 @@ class SoftwareConfig(BASE, HeatBase): name = sqlalchemy.Column('name', sqlalchemy.String(255), nullable=True) group = sqlalchemy.Column('group', sqlalchemy.String(255)) - config = sqlalchemy.Column('config', LongText) - io = sqlalchemy.Column('io', Json) + config = sqlalchemy.Column('config', Json) tenant = sqlalchemy.Column( 'tenant', sqlalchemy.String(256), nullable=False) diff --git a/heat/engine/api.py b/heat/engine/api.py index 223540a778..913b84af81 100644 --- a/heat/engine/api.py +++ b/heat/engine/api.py @@ -317,10 +317,10 @@ def format_software_config(sc): api.SOFTWARE_CONFIG_ID: sc.id, api.SOFTWARE_CONFIG_NAME: sc.name, api.SOFTWARE_CONFIG_GROUP: sc.group, - api.SOFTWARE_CONFIG_CONFIG: sc.config, - api.SOFTWARE_CONFIG_INPUTS: sc.io['inputs'], - api.SOFTWARE_CONFIG_OUTPUTS: sc.io['outputs'], - api.SOFTWARE_CONFIG_OPTIONS: sc.io['options'] + api.SOFTWARE_CONFIG_CONFIG: sc.config['config'], + api.SOFTWARE_CONFIG_INPUTS: sc.config['inputs'], + api.SOFTWARE_CONFIG_OUTPUTS: sc.config['outputs'], + api.SOFTWARE_CONFIG_OPTIONS: sc.config['options'] } return result diff --git a/heat/engine/service.py b/heat/engine/service.py index c8330349a8..efb8d674de 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -1080,14 +1080,15 @@ class EngineService(service.Service): @request_context def create_software_config(self, cnxt, group, name, config, inputs, outputs, options): + sc = db_api.software_config_create(cnxt, { 'group': group, 'name': name, - 'config': config, - 'io': { + 'config': { 'inputs': inputs, 'outputs': outputs, - 'options': options + 'options': options, + 'config': config }, 'tenant': cnxt.tenant_id}) return api.format_software_config(sc) diff --git a/heat/tests/db/test_migrations.py b/heat/tests/db/test_migrations.py index 24bfaa3a21..16f7ba38a3 100644 --- a/heat/tests/db/test_migrations.py +++ b/heat/tests/db/test_migrations.py @@ -234,3 +234,6 @@ class TestHeatMigrations(test_migrations.BaseMigrationTestCase, def _check_036(self, engine, data): self.assertColumnExists(engine, 'stack', 'stack_user_project_id') + + def _check_038(self, engine, data): + self.assertColumnNotExists(engine, 'software_config', 'io') diff --git a/heat/tests/test_engine_api_utils.py b/heat/tests/test_engine_api_utils.py index 35c96677c2..fc5e97a5d4 100644 --- a/heat/tests/test_engine_api_utils.py +++ b/heat/tests/test_engine_api_utils.py @@ -710,12 +710,12 @@ class FormatSoftwareConfigDeploymentTest(HeatTestCase): config = mock.Mock() config.name = 'config_mysql' config.group = 'Heat::Shell' - config.config = '#!/bin/bash\n' config.id = str(uuid.uuid4()) - config.io = { + config.config = { 'inputs': [{'name': 'bar'}], 'outputs': [{'name': 'result'}], - 'options': {} + 'options': {}, + 'config': '#!/bin/bash\n' } return config diff --git a/heat/tests/test_sqlalchemy_api.py b/heat/tests/test_sqlalchemy_api.py index 55099e12cf..b777c12093 100644 --- a/heat/tests/test_sqlalchemy_api.py +++ b/heat/tests/test_sqlalchemy_api.py @@ -622,16 +622,19 @@ class SqlAlchemyTest(HeatTestCase): db_api.software_config_get, self.ctx, str(uuid.uuid4())) - io = {'inputs': [{'name': 'foo'}, {'name': 'bar'}], - 'outputs': [{'name': 'result'}]} - tenant_id = self.ctx.tenant_id conf = ('#!/bin/bash\n' 'echo "$bar and $foo"\n') + config = { + 'inputs': [{'name': 'foo'}, {'name': 'bar'}], + 'outputs': [{'name': 'result'}], + 'config': conf, + 'options': {} + } + tenant_id = self.ctx.tenant_id values = {'name': 'config_mysql', 'tenant': tenant_id, 'group': 'Heat::Shell', - 'config': conf, - 'io': io} + 'config': config} config = db_api.software_config_create( self.ctx, values) config_id = config.id @@ -640,8 +643,7 @@ class SqlAlchemyTest(HeatTestCase): self.assertEqual('config_mysql', config.name) self.assertEqual(tenant_id, config.tenant) self.assertEqual('Heat::Shell', config.group) - self.assertEqual(conf, config.config) - self.assertEqual(io, config.io) + self.assertEqual(conf, config.config['config']) self.ctx.tenant_id = None self.assertRaises( exception.NotFound,