diff --git a/bin/trove-manage b/bin/trove-manage index 5c0c501af5..2764a1009b 100755 --- a/bin/trove-manage +++ b/bin/trove-manage @@ -67,19 +67,21 @@ class Commands(object): kwargs[arg] = getattr(CONF.action, arg) exec_method(**kwargs) - def datastore_update(self, datastore_name, manager, default_version): + def datastore_update(self, datastore_name, default_version): try: - datastore_models.update_datastore(datastore_name, manager, + datastore_models.update_datastore(datastore_name, default_version) print("Datastore '%s' updated." % datastore_name) except exception.DatastoreVersionNotFound as e: print(e) - def datastore_version_update(self, datastore, version_name, image_id, - packages, active): + def datastore_version_update(self, datastore, version_name, manager, + image_id, packages, active): try: datastore_models.update_datastore_version(datastore, - version_name, image_id, + version_name, + manager, + image_id, packages, active) print("Datastore version '%s' updated." % version_name) except exception.DatastoreNotFound as e: @@ -100,22 +102,27 @@ def main(): def actions(subparser): parser = subparser.add_parser('db_sync') parser.add_argument('--repo_path') + parser = subparser.add_parser('db_upgrade') parser.add_argument('--version') parser.add_argument('--repo_path') + parser = subparser.add_parser('db_downgrade') parser.add_argument('version') parser.add_argument('--repo_path') + parser = subparser.add_parser('datastore_update') parser.add_argument('datastore_name') - parser.add_argument('manager') parser.add_argument('default_version') + parser = subparser.add_parser('datastore_version_update') parser.add_argument('datastore') parser.add_argument('version_name') + parser.add_argument('manager') parser.add_argument('image_id') parser.add_argument('packages') parser.add_argument('active') + parser = subparser.add_parser('db_wipe') parser.add_argument('repo_path') diff --git a/run_tests.py b/run_tests.py index 7cbf7874bc..91ed7456e4 100644 --- a/run_tests.py +++ b/run_tests.py @@ -73,17 +73,20 @@ def initialize_trove(config_file): def datastore_init(): # Adds the datastore for mysql (needed to make most calls work). from trove.datastore import models + models.DBDatastore.create(id="a00000a0-00a0-0a00-00a0-000a000000aa", - name=CONFIG.dbaas_datastore, manager='mysql', + name=CONFIG.dbaas_datastore, default_version_id= "b00000b0-00b0-0b00-00b0-000b000000bb") models.DBDatastore.create(id="e00000e0-00e0-0e00-00e0-000e000000ee", - name='Test_Datastore_1', manager='manager1', + name='Test_Datastore_1', default_version_id=None) + models.DBDatastoreVersion.create(id="b00000b0-00b0-0b00-00b0-000b000000bb", datastore_id= "a00000a0-00a0-0a00-00a0-000a000000aa", name=CONFIG.dbaas_datastore_version, + manager="mysql", image_id= 'c00000c0-00c0-0c00-00c0-000c000000cc', packages='test packages', @@ -92,6 +95,7 @@ def datastore_init(): datastore_id= "a00000a0-00a0-0a00-00a0-000a000000aa", name='mysql_inactive_version', + manager="mysql", image_id= 'c00000c0-00c0-0c00-00c0-000c000000cc', packages=None, active=0) diff --git a/trove/datastore/models.py b/trove/datastore/models.py index 57369962d6..22958340ee 100644 --- a/trove/datastore/models.py +++ b/trove/datastore/models.py @@ -21,8 +21,10 @@ from trove.common import exception from trove.common import utils from trove.db import models as dbmodels from trove.db import get_db_api +from trove.openstack.common import log as logging +LOG = logging.getLogger(__name__) CONF = cfg.CONF db_api = get_db_api() @@ -36,13 +38,13 @@ def persisted_models(): class DBDatastore(dbmodels.DatabaseModelBase): - _data_fields = ['id', 'name', 'manager', 'default_version_id'] + _data_fields = ['id', 'name', 'default_version_id'] class DBDatastoreVersion(dbmodels.DatabaseModelBase): - _data_fields = ['id', 'datastore_id', 'name', 'image_id', 'packages', - 'active'] + _data_fields = ['id', 'datastore_id', 'name', 'manager', 'image_id', + 'packages', 'active'] class Datastore(object): @@ -68,10 +70,6 @@ class Datastore(object): def name(self): return self.db_info.name - @property - def manager(self): - return self.db_info.manager - @property def default_version_id(self): return self.db_info.default_version_id @@ -130,6 +128,10 @@ class DatastoreVersion(object): def active(self): return self.db_info.active + @property + def manager(self): + return self.db_info.manager + class DatastoreVersions(object): @@ -166,7 +168,7 @@ def get_datastore_version(type=None, version=None): return (datastore, datastore_version) -def update_datastore(name, manager, default_version): +def update_datastore(name, default_version): db_api.configure_db(CONF) if default_version: version = DatastoreVersion.load(default_version) @@ -180,13 +182,13 @@ def update_datastore(name, manager, default_version): datastore = DBDatastore() datastore.id = utils.generate_uuid() datastore.name = name - datastore.manager = manager if default_version: datastore.default_version_id = version.id db_api.save(datastore) -def update_datastore_version(datastore, name, image_id, packages, active): +def update_datastore_version(datastore, name, manager, image_id, packages, + active): db_api.configure_db(CONF) datastore = Datastore.load(datastore) try: @@ -197,6 +199,7 @@ def update_datastore_version(datastore, name, image_id, packages, active): version.id = utils.generate_uuid() version.name = name version.datastore_id = datastore.id + version.manager = manager version.image_id = image_id version.packages = packages version.active = active diff --git a/trove/db/sqlalchemy/migrate_repo/versions/017_update_datastores.py b/trove/db/sqlalchemy/migrate_repo/versions/017_update_datastores.py new file mode 100644 index 0000000000..a043b29018 --- /dev/null +++ b/trove/db/sqlalchemy/migrate_repo/versions/017_update_datastores.py @@ -0,0 +1,63 @@ +# 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.schema import Column +from sqlalchemy.schema import MetaData +from sqlalchemy.sql.expression import select + +from trove.db.sqlalchemy.migrate_repo.schema import String +from trove.db.sqlalchemy.migrate_repo.schema import Table + + +def migrate_datastore_manager(datastores, datastore_versions): + versions = select([datastore_versions]).execute() + for ds_v in versions: + ds = select([datastores]).\ + where(datastores.c.id == ds_v.datastore_id).\ + execute().fetchone() + datastore_versions.update().\ + where(datastore_versions.c.id == ds_v.id).\ + values(manager=ds.manager).\ + execute() + + +def upgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + datastores = Table('datastores', meta, autoload=True) + datastore_versions = Table('datastore_versions', meta, autoload=True) + + # add column to datastore_versions + manager = Column('manager', String(255)) + datastore_versions.create_column(manager) + migrate_datastore_manager(datastores, datastore_versions) + + # drop column from datastores + datastores.drop_column('manager') + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + datastores = Table('datastores', meta, autoload=True) + datastore_versions = Table('datastore_versions', meta, autoload=True) + + # drop column from datastore_versions + datastore_versions.drop_column('manager') + + # add column to datastores + manager = Column('manager', String(255)) + datastores.create_column(manager) diff --git a/trove/extensions/mgmt/instances/models.py b/trove/extensions/mgmt/instances/models.py index 9d056dcc59..e45290ffcb 100644 --- a/trove/extensions/mgmt/instances/models.py +++ b/trove/extensions/mgmt/instances/models.py @@ -207,7 +207,7 @@ class NotificationTransformer(object): 'tenant_id': instance.tenant_id } payload['service_id'] = self._get_service_id( - instance.datastore.manager, CONF.notification_service_id) + instance.datastore_version.manager, CONF.notification_service_id) return payload def __call__(self): @@ -250,7 +250,8 @@ class NovaNotificationTransformer(NotificationTransformer): instances): message = { 'instance_type': self._lookup_flavor(instance.flavor_id), - 'user_id': instance.server.user_id} + 'user_id': instance.server.user_id + } message.update(self.transform_instance(instance, audit_start, audit_end)) diff --git a/trove/instance/models.py b/trove/instance/models.py index 3dc660034a..30127ff3a2 100644 --- a/trove/instance/models.py +++ b/trove/instance/models.py @@ -509,7 +509,7 @@ class Instance(BuiltInstance): task_api.API(context).create_instance(db_info.id, name, flavor, image_id, databases, users, - datastore.manager, + datastore_version.manager, datastore_version.packages, volume_size, backup_id, availability_zone, diff --git a/trove/taskmanager/api.py b/trove/taskmanager/api.py index aa9fd0cb94..b8cf8e0bfc 100644 --- a/trove/taskmanager/api.py +++ b/trove/taskmanager/api.py @@ -111,7 +111,8 @@ class API(proxy.RpcProxy): image_id=image_id, databases=databases, users=users, - datastore_manager=datastore_manager, + datastore_manager= + datastore_manager, packages=packages, volume_size=volume_size, backup_id=backup_id, diff --git a/trove/taskmanager/models.py b/trove/taskmanager/models.py index aafeabadbb..063aa091d5 100644 --- a/trove/taskmanager/models.py +++ b/trove/taskmanager/models.py @@ -117,7 +117,7 @@ class NotifyMixin(object): }) payload['service_id'] = self._get_service_id( - self.datastore.manager, CONF.notification_service_id) + self.datastore_version.manager, CONF.notification_service_id) # Update payload with all other kwargs payload.update(kwargs) @@ -1015,8 +1015,11 @@ class ResizeAction(ResizeActionBase): % self.instance.id) LOG.debug(_("Repairing config.")) try: - config = self._render_config(self.instance.datastore.manager, - self.old_flavor, self.instance.id) + config = self._render_config( + self.instance.datastore_version.manager, + self.old_flavor, + self.instance.id + ) config = {'config_contents': config.config_contents} self.instance.guest.reset_configuration(config) except GuestTimeout: @@ -1036,7 +1039,7 @@ class ResizeAction(ResizeActionBase): modify_at=timeutils.isotime(self.instance.updated)) def _start_mysql(self): - config = self._render_config(self.instance.datastore.manager, + config = self._render_config(self.instance.datastore_version.manager, self.new_flavor, self.instance.id) self.instance.guest.start_db_with_conf_changes(config.config_contents) diff --git a/trove/tests/unittests/mgmt/test_models.py b/trove/tests/unittests/mgmt/test_models.py index 7d129bd735..bda76d0eda 100644 --- a/trove/tests/unittests/mgmt/test_models.py +++ b/trove/tests/unittests/mgmt/test_models.py @@ -81,10 +81,19 @@ class TestNotificationTransformer(MockMgmtInstanceTest): when(DatabaseModelBase).find_all(deleted=False).thenReturn( [db_instance]) - stub_datastore = mock() - stub_datastore.datastore_id = "stub" - stub_datastore.manager = "mysql" - when(DatabaseModelBase).find_by(id=any()).thenReturn(stub_datastore) + stub_dsv_db_info = mock(datastore_models.DBDatastoreVersion) + stub_dsv_db_info.id = "test_datastore_version" + stub_dsv_db_info.datastore_id = "mysql_test_version" + stub_dsv_db_info.name = "test_datastore_name" + stub_dsv_db_info.image_id = "test_datastore_image_id" + stub_dsv_db_info.packages = "test_datastore_pacakges" + stub_dsv_db_info.active = 1 + stub_dsv_db_info.manager = "mysql" + stub_datastore_version = datastore_models.DatastoreVersion( + stub_dsv_db_info) + when(DatabaseModelBase).find_by(id=any()).thenReturn( + stub_datastore_version) + when(DatabaseModelBase).find_by(instance_id='1').thenReturn( InstanceServiceStatus(rd_instance.ServiceStatuses.BUILDING)) @@ -141,6 +150,19 @@ class TestNovaNotificationTransformer(MockMgmtInstanceTest): db_instance = MockMgmtInstanceTest.build_db_instance( status, task_status=InstanceTasks.BUILDING) + stub_dsv_db_info = mock(datastore_models.DBDatastoreVersion) + stub_dsv_db_info.id = "test_datastore_version" + stub_dsv_db_info.datastore_id = "mysql_test_version" + stub_dsv_db_info.name = "test_datastore_name" + stub_dsv_db_info.image_id = "test_datastore_image_id" + stub_dsv_db_info.packages = "test_datastore_pacakges" + stub_dsv_db_info.active = 1 + stub_dsv_db_info.manager = "mysql" + stub_datastore_version = datastore_models.DatastoreVersion( + stub_dsv_db_info) + when(DatabaseModelBase).find_by(id=any()).thenReturn( + stub_datastore_version) + server = mock(Server) server.user_id = 'test_user_id' mgmt_instance = mgmtmodels.SimpleMgmtInstance(self.context, @@ -179,8 +201,14 @@ class TestNovaNotificationTransformer(MockMgmtInstanceTest): server = mock(Server) server.user_id = 'test_user_id' + stub_datastore_version = mock() + stub_datastore_version.id = "stub_datastore_version" + stub_datastore_version.manager = "m0ng0" + when(datastore_models. + DatastoreVersion).load(any()).thenReturn(stub_datastore_version) + stub_datastore = mock() - stub_datastore.manager = "m0ng0" + stub_datastore.default_datastore_version = "stub_datastore_version" when(datastore_models. Datastore).load(any()).thenReturn(stub_datastore) mgmt_instance = mgmtmodels.SimpleMgmtInstance(self.context,