Make sure all "updated_at" fields store fractional seconds

If update happen really fast (subsecond) we can't distinguish
one update from the next, so when using mysql turn on
fractional second DATETIME.

Just to be consistent, change the created_at fields at the same
time.

Change-Id: I949fedbfda58348b051072bba98ed59897824f6e
Closes-bug: #1480739
This commit is contained in:
Angus Salkeld 2015-08-04 09:38:47 +10:00
parent a11494b205
commit 3b2d14ad99
2 changed files with 73 additions and 1 deletions

View File

@ -0,0 +1,43 @@
#
# 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 oslo_log import log as logging
import sqlalchemy
from sqlalchemy import dialects
from heat.common.i18n import _LW
LOG = logging.getLogger(__name__)
def upgrade(migrate_engine):
meta = sqlalchemy.MetaData(bind=migrate_engine)
if migrate_engine.name == 'mysql':
if migrate_engine.dialect.server_version_info < (5, 6, 4):
LOG.warn(_LW('Migration 065 could not be applied as the MySQl '
'server version is below 5.6.4. Once the server has '
'been upgraded this migration will need to be '
'manually applied.'))
return
# Note that this feature was only added in 5.6.4
# see: http://docs.sqlalchemy.org/en/rel_0_9/dialects/mysql.html
for tn in ['raw_template', 'user_creds', 'stack',
'resource', 'resource_data', 'event',
'watch_rule', 'watch_data', 'snapshot',
'software_deployment', 'software_config',
'sync_point', 'service', 'stack_tag']:
table = sqlalchemy.Table(tn, meta, autoload=True)
# Use the fsp parameter (fractional seconds parameter) to allow
# subsecond timestamps.
table.c.updated_at.alter(type=dialects.mysql.DATETIME(fsp=6))
table.c.created_at.alter(type=dialects.mysql.DATETIME(fsp=6))

View File

@ -31,6 +31,7 @@ from oslo_db.sqlalchemy import utils
from oslo_serialization import jsonutils
import six
import sqlalchemy
from sqlalchemy import dialects
import testtools
from heat.db.sqlalchemy import migrate_repo
@ -622,7 +623,35 @@ class HeatMigrationsCheckers(test_migrations.WalkVersionsMixin,
class TestHeatMigrationsMySQL(HeatMigrationsCheckers,
test_base.MySQLOpportunisticTestCase):
pass
def _check_065(self, engine, data):
server_ver = engine.dialect.server_version_info
if server_ver < (5, 6, 4):
self.skip('MySQL server version too old %s' %
six.text_type(server_ver))
for tab_name in ['raw_template', 'user_creds', 'stack',
'resource', 'resource_data', 'event',
'watch_rule', 'watch_data', 'snapshot',
'software_deployment', 'software_config',
'sync_point', 'service', 'stack_tag']:
self.assertColumnType(engine, tab_name, 'updated_at',
dialects.mysql.DATETIME)
self.assertColumnType(engine, tab_name, 'created_at',
dialects.mysql.DATETIME)
# test on one table that we can write and read a subsecond
# datetime.
test_dt = datetime.datetime.now()
if test_dt.microsecond == 0:
test_dt.microsecond = 814673
raw_table = utils.get_table(engine, 'raw_template')
templ = [dict(id=15, template='{}', files='{}',
updated_at=test_dt)]
engine.execute(raw_table.insert(), templ)
temps_in_db = list(raw_table.select().
where(raw_table.c.id == '15').execute())
self.assertEqual(1, len(temps_in_db))
self.assertEqual(test_dt, temps_in_db[0].updated_at)
class TestHeatMigrationsPostgreSQL(HeatMigrationsCheckers,