diff --git a/trove/configuration/models.py b/trove/configuration/models.py index eefd11abb3..7f91469c50 100644 --- a/trove/configuration/models.py +++ b/trove/configuration/models.py @@ -196,7 +196,7 @@ class Configuration(object): class DBConfiguration(dbmodels.DatabaseModelBase): _data_fields = ['name', 'description', 'tenant_id', 'datastore_version_id', - 'deleted', 'deleted_at'] + 'deleted', 'deleted_at', 'created', 'updated'] class ConfigurationParameter(dbmodels.DatabaseModelBase): diff --git a/trove/configuration/service.py b/trove/configuration/service.py index 397d1cc389..1a3ae0338d 100644 --- a/trove/configuration/service.py +++ b/trove/configuration/service.py @@ -50,6 +50,11 @@ class ConfigurationsController(wsgi.Controller): configuration = models.Configuration.load(context, id) configuration_items = models.Configuration.load_items(context, id) + configuration.instance_count = instances_models.DBInstance.find_all( + tenant_id=context.tenant, + configuration_id=configuration.id, + deleted=False).count() + return wsgi.Result(views.DetailedConfigurationView( configuration, configuration_items).data(), 200) diff --git a/trove/configuration/views.py b/trove/configuration/views.py index d410b51ea1..37b1308ca0 100644 --- a/trove/configuration/views.py +++ b/trove/configuration/views.py @@ -29,6 +29,8 @@ class ConfigurationView(object): "name": self.configuration.name, "description": self.configuration.description, "datastore_version_id": self.configuration.datastore_version_id, + "created": self.configuration.created, + "updated": self.configuration.updated } return {"configuration": configuration_dict} @@ -93,6 +95,9 @@ class DetailedConfigurationView(object): "description": self.configuration.description, "values": values, "datastore_version_id": self.configuration.datastore_version_id, + "created": self.configuration.created, + "updated": self.configuration.updated, + "instance_count": getattr(self.configuration, "instance_count", 0) } return {"configuration": configuration_dict} diff --git a/trove/db/sqlalchemy/migrate_repo/versions/031_add_timestamps_to_configurations.py b/trove/db/sqlalchemy/migrate_repo/versions/031_add_timestamps_to_configurations.py new file mode 100644 index 0000000000..8ca717a48b --- /dev/null +++ b/trove/db/sqlalchemy/migrate_repo/versions/031_add_timestamps_to_configurations.py @@ -0,0 +1,35 @@ +# Copyright 2014 Rackspace Hosting +# +# 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 trove.db.sqlalchemy.migrate_repo.schema import Table +from trove.db.sqlalchemy.migrate_repo.schema import DateTime + + +def upgrade(migrate_engine): + meta = MetaData(bind=migrate_engine) + configurations = Table('configurations', meta, autoload=True) + created = Column('created', DateTime()) + updated = Column('updated', DateTime()) + configurations.create_column(created) + configurations.create_column(updated) + + +def downgrade(migrate_engine): + meta = MetaData(bind=migrate_engine) + configurations = Table('configurations', meta, autoload=True) + configurations.drop_column('created') + configurations.drop_column('updated') diff --git a/trove/tests/api/configurations.py b/trove/tests/api/configurations.py index 2a32e701d7..3f90b34ec6 100644 --- a/trove/tests/api/configurations.py +++ b/trove/tests/api/configurations.py @@ -15,6 +15,7 @@ import json +from time import sleep from datetime import datetime from proboscis import SkipTest from proboscis import test @@ -57,6 +58,14 @@ sql_variables = [ ] +def _is_valid_timestamp(time_string): + try: + datetime.strptime(time_string, "%Y-%m-%dT%H:%M:%S") + except ValueError: + return False + return True + + # helper methods to validate configuration is applied to instance def _execute_query(host, user_name, password, query): print(host, user_name, password, query) @@ -226,6 +235,8 @@ class CreateConfigurations(object): # test being able to update and insert new parameter name and values # to an existing configuration values = '{"join_buffer_size": 1048576, "connect_timeout": 60}' + # ensure updated timestamp is different than created + sleep(1) instance_info.dbaas.configurations.edit(configuration_info.id, values) resp, body = instance_info.dbaas.client.last_response @@ -291,8 +302,23 @@ class AfterConfigurationsCreation(object): check.has_field("name", basestring) check.has_field("description", basestring) check.has_field("values", dict) + check.has_field("created", basestring) + check.has_field("updated", basestring) + check.has_field("instance_count", int) print(result.values) + + # check for valid timestamps + assert_true(_is_valid_timestamp(result.created)) + assert_true(_is_valid_timestamp(result.updated)) + + # check that created and updated timestamps differ, since + # test_appending_to_existing_configuration should have changed the + # updated timestamp + assert_not_equal(result.created, result.updated) + + assert_equal(result.instance_count, 1) + with CollectionCheck("configuration_values", result.values) as check: # check each item has the correct type according to the rules for (item_key, item_val) in result.values.iteritems(): @@ -423,6 +449,18 @@ class ListConfigurations(object): _test_configuration_is_applied_to_instance(instance_info, configuration_id) + @test(depends_on=[test_configurations_list]) + def test_compare_list_and_details_timestamps(self): + # compare config timestamps between list and details calls + result = instance_info.dbaas.configurations.list() + list_config = [config for config in result if + config.id == configuration_info.id] + assert_equal(1, len(list_config)) + details_config = instance_info.dbaas.configurations.get( + configuration_info.id) + assert_equal(list_config[0].created, details_config.created) + assert_equal(list_config[0].updated, details_config.updated) + @test(runs_after=[ListConfigurations], groups=[GROUP]) class StartInstanceWithConfiguration(object): @@ -557,6 +595,7 @@ class DeleteConfigurations(object): assert_equal(configuration_info.id, result.id) assert_equal(configuration_info.name, result.name) assert_equal(configuration_info.description, result.description) + assert_equal(result.instance_count, 0) print(configuration_instance.id) print(instance_info.id)