From 519bd2451d8b3aff6661d18e340b8f31a69e1091 Mon Sep 17 00:00:00 2001 From: Zhiteng Huang Date: Fri, 13 Jul 2012 13:58:25 +0800 Subject: [PATCH] Convert Cinder to use openstack-common timeutils This patch is part of effort to get Cinder to use openstack-common package. This part is to replace time related functions in utils.py with 'timeutils' module. Implement blueprint cinder-common-timeutils Change-Id: Ic5e9e317a95a7399f0604823eec76b3642a0c1b1 --- bin/cinder-manage | 1 - cinder/common/memorycache.py | 5 +- cinder/context.py | 7 +- cinder/db/sqlalchemy/api.py | 16 +-- cinder/db/sqlalchemy/models.py | 7 +- cinder/notifier/api.py | 5 +- cinder/scheduler/driver.py | 3 +- cinder/test.py | 3 +- cinder/tests/api/openstack/fakes.py | 3 +- cinder/tests/scheduler/test_scheduler.py | 5 +- cinder/tests/test_utils.py | 118 ++--------------------- cinder/utils.py | 82 +--------------- cinder/volume/api.py | 3 +- cinder/volume/manager.py | 3 +- 14 files changed, 45 insertions(+), 216 deletions(-) diff --git a/bin/cinder-manage b/bin/cinder-manage index 0cc6d82c8..195e8d9c4 100755 --- a/bin/cinder-manage +++ b/bin/cinder-manage @@ -192,7 +192,6 @@ class HostCommands(object): print "%-25s\t%-15s" % (_('host'), _('zone')) ctxt = context.get_admin_context() - now = utils.utcnow() services = db.service_get_all(ctxt) if zone: services = [s for s in services if s['availability_zone'] == zone] diff --git a/cinder/common/memorycache.py b/cinder/common/memorycache.py index 564526092..1686d5141 100644 --- a/cinder/common/memorycache.py +++ b/cinder/common/memorycache.py @@ -19,6 +19,7 @@ """Super simple fake memcache client.""" from cinder import utils +from cinder.openstack.common import timeutils class Client(object): @@ -35,7 +36,7 @@ class Client(object): for k in self.cache.keys(): (timeout, _value) = self.cache[k] - if timeout and utils.utcnow_ts() >= timeout: + if timeout and timeutils.utcnow_ts() >= timeout: del self.cache[k] return self.cache.get(key, (0, None))[1] @@ -44,7 +45,7 @@ class Client(object): """Sets the value for a key.""" timeout = 0 if time != 0: - timeout = utils.utcnow_ts() + time + timeout = timeutils.utcnow_ts() + time self.cache[key] = (timeout, value) return True diff --git a/cinder/context.py b/cinder/context.py index a9b5519c2..12ad796b3 100644 --- a/cinder/context.py +++ b/cinder/context.py @@ -23,6 +23,7 @@ import copy from cinder import log as logging from cinder.openstack.common import local +from cinder.openstack.common import timeutils from cinder import utils @@ -70,9 +71,9 @@ class RequestContext(object): self.read_deleted = read_deleted self.remote_address = remote_address if not timestamp: - timestamp = utils.utcnow() + timestamp = timeutils.utcnow() if isinstance(timestamp, basestring): - timestamp = utils.parse_strtime(timestamp) + timestamp = timeutils.parse_strtime(timestamp) self.timestamp = timestamp if not request_id: request_id = generate_request_id() @@ -107,7 +108,7 @@ class RequestContext(object): 'read_deleted': self.read_deleted, 'roles': self.roles, 'remote_address': self.remote_address, - 'timestamp': utils.strtime(self.timestamp), + 'timestamp': timeutils.strtime(self.timestamp), 'request_id': self.request_id, 'auth_token': self.auth_token, 'quota_class': self.quota_class} diff --git a/cinder/db/sqlalchemy/api.py b/cinder/db/sqlalchemy/api.py index 714f7429e..60954de7c 100644 --- a/cinder/db/sqlalchemy/api.py +++ b/cinder/db/sqlalchemy/api.py @@ -465,7 +465,7 @@ def volume_destroy(context, volume_id): session.query(models.Volume).\ filter_by(id=volume_id).\ update({'deleted': True, - 'deleted_at': utils.utcnow(), + 'deleted_at': timeutils.utcnow(), 'updated_at': literal_column('updated_at')}) session.query(models.IscsiTarget).\ filter_by(volume_id=volume_id).\ @@ -473,7 +473,7 @@ def volume_destroy(context, volume_id): session.query(models.VolumeMetadata).\ filter_by(volume_id=volume_id).\ update({'deleted': True, - 'deleted_at': utils.utcnow(), + 'deleted_at': timeutils.utcnow(), 'updated_at': literal_column('updated_at')}) @@ -603,7 +603,7 @@ def volume_metadata_delete(context, volume_id, key): _volume_metadata_get_query(context, volume_id).\ filter_by(key=key).\ update({'deleted': True, - 'deleted_at': utils.utcnow(), + 'deleted_at': timeutils.utcnow(), 'updated_at': literal_column('updated_at')}) @@ -679,7 +679,7 @@ def snapshot_destroy(context, snapshot_id): session.query(models.Snapshot).\ filter_by(id=snapshot_id).\ update({'deleted': True, - 'deleted_at': utils.utcnow(), + 'deleted_at': timeutils.utcnow(), 'updated_at': literal_column('updated_at')}) @@ -775,7 +775,7 @@ def migration_get_by_instance_and_status(context, instance_uuid, status): @require_admin_context def migration_get_all_unconfirmed(context, confirm_window, session=None): - confirm_window = datetime.datetime.utcnow() - datetime.timedelta( + confirm_window = timeutils.utcnow() - datetime.timedelta( seconds=confirm_window) return model_query(context, models.Migration, session=session, @@ -875,12 +875,12 @@ def volume_type_destroy(context, name): session.query(models.VolumeTypes).\ filter_by(id=volume_type_id).\ update({'deleted': True, - 'deleted_at': utils.utcnow(), + 'deleted_at': timeutils.utcnow(), 'updated_at': literal_column('updated_at')}) session.query(models.VolumeTypeExtraSpecs).\ filter_by(volume_type_id=volume_type_id).\ update({'deleted': True, - 'deleted_at': utils.utcnow(), + 'deleted_at': timeutils.utcnow(), 'updated_at': literal_column('updated_at')}) @@ -910,7 +910,7 @@ def volume_type_extra_specs_delete(context, volume_type_id, key): _volume_type_extra_specs_query(context, volume_type_id).\ filter_by(key=key).\ update({'deleted': True, - 'deleted_at': utils.utcnow(), + 'deleted_at': timeutils.utcnow(), 'updated_at': literal_column('updated_at')}) diff --git a/cinder/db/sqlalchemy/models.py b/cinder/db/sqlalchemy/models.py index 460a855dc..1b7e43f86 100644 --- a/cinder/db/sqlalchemy/models.py +++ b/cinder/db/sqlalchemy/models.py @@ -32,6 +32,7 @@ from cinder.db.sqlalchemy.session import get_session from cinder import exception from cinder import flags from cinder import utils +from cinder.openstack.common import timeutils FLAGS = flags.FLAGS @@ -42,8 +43,8 @@ class CinderBase(object): """Base class for Cinder Models.""" __table_args__ = {'mysql_engine': 'InnoDB'} __table_initialized__ = False - created_at = Column(DateTime, default=utils.utcnow) - updated_at = Column(DateTime, onupdate=utils.utcnow) + created_at = Column(DateTime, default=timeutils.utcnow) + updated_at = Column(DateTime, onupdate=timeutils.utcnow) deleted_at = Column(DateTime) deleted = Column(Boolean, default=False) metadata = None @@ -64,7 +65,7 @@ class CinderBase(object): def delete(self, session=None): """Delete this object.""" self.deleted = True - self.deleted_at = utils.utcnow() + self.deleted_at = timeutils.utcnow() self.save(session=session) def __setitem__(self, key, value): diff --git a/cinder/notifier/api.py b/cinder/notifier/api.py index 27c9e8421..f144b1536 100644 --- a/cinder/notifier/api.py +++ b/cinder/notifier/api.py @@ -20,6 +20,7 @@ from cinder import utils from cinder import log as logging from cinder.openstack.common import cfg from cinder.openstack.common import importutils +from cinder.openstack.common import timeutils LOG = logging.getLogger(__name__) @@ -105,7 +106,7 @@ def notify(publisher_id, event_type, priority, payload): {'message_id': str(uuid.uuid4()), 'publisher_id': 'compute.host1', - 'timestamp': utils.utcnow(), + 'timestamp': timeutils.utcnow(), 'priority': 'WARN', 'event_type': 'compute.create_instance', 'payload': {'instance_id': 12, ... }} @@ -124,7 +125,7 @@ def notify(publisher_id, event_type, priority, payload): event_type=event_type, priority=priority, payload=payload, - timestamp=str(utils.utcnow())) + timestamp=str(timeutils.utcnow())) try: driver.notify(msg) except Exception, e: diff --git a/cinder/scheduler/driver.py b/cinder/scheduler/driver.py index 1696cbd28..49420d848 100644 --- a/cinder/scheduler/driver.py +++ b/cinder/scheduler/driver.py @@ -26,6 +26,7 @@ from cinder import flags from cinder import log as logging from cinder.openstack.common import cfg from cinder.openstack.common import importutils +from cinder.openstack.common import timeutils from cinder import rpc from cinder.rpc import common as rpc_common from cinder import utils @@ -49,7 +50,7 @@ def cast_to_volume_host(context, host, method, update_db=True, **kwargs): if update_db: volume_id = kwargs.get('volume_id', None) if volume_id is not None: - now = utils.utcnow() + now = timeutils.utcnow() db.volume_update(context, volume_id, {'host': host, 'scheduled_at': now}) rpc.cast(context, diff --git a/cinder/test.py b/cinder/test.py index 434a7c6b9..fb88c89c0 100644 --- a/cinder/test.py +++ b/cinder/test.py @@ -36,6 +36,7 @@ import stubout from cinder import flags from cinder import log as logging from cinder.openstack.common import cfg +from cinder.openstack.common import timeutils from cinder import utils from cinder import service from cinder import tests @@ -126,7 +127,7 @@ class TestCase(unittest.TestCase): # NOTE(vish): We need a better method for creating fixtures for tests # now that we have some required db setup for the system # to work properly. - self.start = utils.utcnow() + self.start = timeutils.utcnow() tests.reset_db() # emulate some of the mox stuff, we can't use the metaclass diff --git a/cinder/tests/api/openstack/fakes.py b/cinder/tests/api/openstack/fakes.py index 959606ffe..f1511b1a7 100644 --- a/cinder/tests/api/openstack/fakes.py +++ b/cinder/tests/api/openstack/fakes.py @@ -34,6 +34,7 @@ from cinder.db.sqlalchemy import models from cinder import exception as exc from cinder import utils from cinder import wsgi +from cinder.openstack.common import timeutils FAKE_UUID = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' @@ -147,7 +148,7 @@ class FakeAuthDatabase(object): @staticmethod def auth_token_create(context, token): - fake_token = FakeToken(created_at=utils.utcnow(), **token) + fake_token = FakeToken(created_at=timeutils.utcnow(), **token) FakeAuthDatabase.data[fake_token.token_hash] = fake_token FakeAuthDatabase.data['id_%i' % fake_token.id] = fake_token return fake_token diff --git a/cinder/tests/scheduler/test_scheduler.py b/cinder/tests/scheduler/test_scheduler.py index cb1adce90..b45413c66 100644 --- a/cinder/tests/scheduler/test_scheduler.py +++ b/cinder/tests/scheduler/test_scheduler.py @@ -28,6 +28,7 @@ from cinder import exception from cinder import flags from cinder.notifier import api as notifier from cinder import rpc +from cinder.openstack.common import timeutils from cinder.rpc import common as rpc_common from cinder.scheduler import driver from cinder.scheduler import manager @@ -236,12 +237,12 @@ class SchedulerDriverModuleTestCase(test.TestCase): 'extra_arg': 'meow'} queue = 'fake_queue' - self.mox.StubOutWithMock(utils, 'utcnow') + self.mox.StubOutWithMock(timeutils, 'utcnow') self.mox.StubOutWithMock(db, 'volume_update') self.mox.StubOutWithMock(db, 'queue_get_for') self.mox.StubOutWithMock(rpc, 'cast') - utils.utcnow().AndReturn('fake-now') + timeutils.utcnow().AndReturn('fake-now') db.volume_update(self.context, 31337, {'host': host, 'scheduled_at': 'fake-now'}) db.queue_get_for(self.context, diff --git a/cinder/tests/test_utils.py b/cinder/tests/test_utils.py index ee946e7d9..2f375eb53 100644 --- a/cinder/tests/test_utils.py +++ b/cinder/tests/test_utils.py @@ -33,6 +33,7 @@ import mox import cinder from cinder import exception from cinder import flags +from cinder.openstack.common import timeutils from cinder import test from cinder import utils @@ -690,10 +691,10 @@ class DeprecationTest(test.TestCase): down_time = 5 self.flags(service_down_time=down_time) - self.mox.StubOutWithMock(utils, 'utcnow') + self.mox.StubOutWithMock(timeutils, 'utcnow') # Up (equal) - utils.utcnow().AndReturn(fts_func(fake_now)) + timeutils.utcnow().AndReturn(fts_func(fake_now)) service = {'updated_at': fts_func(fake_now - down_time), 'created_at': fts_func(fake_now - down_time)} self.mox.ReplayAll() @@ -702,7 +703,7 @@ class DeprecationTest(test.TestCase): self.mox.ResetAll() # Up - utils.utcnow().AndReturn(fts_func(fake_now)) + timeutils.utcnow().AndReturn(fts_func(fake_now)) service = {'updated_at': fts_func(fake_now - down_time + 1), 'created_at': fts_func(fake_now - down_time + 1)} self.mox.ReplayAll() @@ -711,7 +712,7 @@ class DeprecationTest(test.TestCase): self.mox.ResetAll() # Down - utils.utcnow().AndReturn(fts_func(fake_now)) + timeutils.utcnow().AndReturn(fts_func(fake_now)) service = {'updated_at': fts_func(fake_now - down_time - 1), 'created_at': fts_func(fake_now - down_time - 1)} self.mox.ReplayAll() @@ -730,111 +731,6 @@ class DeprecationTest(test.TestCase): self.assertEquals(h1, h2) -class Iso8601TimeTest(test.TestCase): - - def _instaneous(self, timestamp, yr, mon, day, hr, min, sec, micro): - self.assertEquals(timestamp.year, yr) - self.assertEquals(timestamp.month, mon) - self.assertEquals(timestamp.day, day) - self.assertEquals(timestamp.hour, hr) - self.assertEquals(timestamp.minute, min) - self.assertEquals(timestamp.second, sec) - self.assertEquals(timestamp.microsecond, micro) - - def _do_test(self, str, yr, mon, day, hr, min, sec, micro, shift): - DAY_SECONDS = 24 * 60 * 60 - timestamp = utils.parse_isotime(str) - self._instaneous(timestamp, yr, mon, day, hr, min, sec, micro) - offset = timestamp.tzinfo.utcoffset(None) - self.assertEqual(offset.seconds + offset.days * DAY_SECONDS, shift) - - def test_zulu(self): - str = '2012-02-14T20:53:07Z' - self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, 0) - - def test_zulu_micros(self): - str = '2012-02-14T20:53:07.123Z' - self._do_test(str, 2012, 02, 14, 20, 53, 7, 123000, 0) - - def test_offset_east(self): - str = '2012-02-14T20:53:07+04:30' - offset = 4.5 * 60 * 60 - self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, offset) - - def test_offset_east_micros(self): - str = '2012-02-14T20:53:07.42+04:30' - offset = 4.5 * 60 * 60 - self._do_test(str, 2012, 02, 14, 20, 53, 7, 420000, offset) - - def test_offset_west(self): - str = '2012-02-14T20:53:07-05:30' - offset = -5.5 * 60 * 60 - self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, offset) - - def test_offset_west_micros(self): - str = '2012-02-14T20:53:07.654321-05:30' - offset = -5.5 * 60 * 60 - self._do_test(str, 2012, 02, 14, 20, 53, 7, 654321, offset) - - def test_compare(self): - zulu = utils.parse_isotime('2012-02-14T20:53:07') - east = utils.parse_isotime('2012-02-14T20:53:07-01:00') - west = utils.parse_isotime('2012-02-14T20:53:07+01:00') - self.assertTrue(east > west) - self.assertTrue(east > zulu) - self.assertTrue(zulu > west) - - def test_compare_micros(self): - zulu = utils.parse_isotime('2012-02-14T20:53:07.6544') - east = utils.parse_isotime('2012-02-14T19:53:07.654321-01:00') - west = utils.parse_isotime('2012-02-14T21:53:07.655+01:00') - self.assertTrue(east < west) - self.assertTrue(east < zulu) - self.assertTrue(zulu < west) - - def test_zulu_roundtrip(self): - str = '2012-02-14T20:53:07Z' - zulu = utils.parse_isotime(str) - self.assertEquals(zulu.tzinfo, iso8601.iso8601.UTC) - self.assertEquals(utils.isotime(zulu), str) - - def test_east_roundtrip(self): - str = '2012-02-14T20:53:07-07:00' - east = utils.parse_isotime(str) - self.assertEquals(east.tzinfo.tzname(None), '-07:00') - self.assertEquals(utils.isotime(east), str) - - def test_west_roundtrip(self): - str = '2012-02-14T20:53:07+11:30' - west = utils.parse_isotime(str) - self.assertEquals(west.tzinfo.tzname(None), '+11:30') - self.assertEquals(utils.isotime(west), str) - - def test_now_roundtrip(self): - str = utils.isotime() - now = utils.parse_isotime(str) - self.assertEquals(now.tzinfo, iso8601.iso8601.UTC) - self.assertEquals(utils.isotime(now), str) - - def test_zulu_normalize(self): - str = '2012-02-14T20:53:07Z' - zulu = utils.parse_isotime(str) - normed = utils.normalize_time(zulu) - self._instaneous(normed, 2012, 2, 14, 20, 53, 07, 0) - - def test_east_normalize(self): - str = '2012-02-14T20:53:07-07:00' - east = utils.parse_isotime(str) - normed = utils.normalize_time(east) - self._instaneous(normed, 2012, 2, 15, 03, 53, 07, 0) - - def test_west_normalize(self): - str = '2012-02-14T20:53:07+21:00' - west = utils.parse_isotime(str) - normed = utils.normalize_time(west) - self._instaneous(normed, 2012, 2, 13, 23, 53, 07, 0) - - class TestGreenLocks(test.TestCase): def test_concurrent_green_lock_succeeds(self): """Verify spawn_n greenthreads with two locks run concurrently. @@ -1035,10 +931,10 @@ class AuditPeriodTest(test.TestCase): day=5, month=3, year=2012) - utils.set_time_override(override_time=self.test_time) + timeutils.set_time_override(override_time=self.test_time) def tearDown(self): - utils.clear_time_override() + timeutils.clear_time_override() super(AuditPeriodTest, self).tearDown() def test_hour(self): diff --git a/cinder/utils.py b/cinder/utils.py index f80fb1431..60bc80a50 100644 --- a/cinder/utils.py +++ b/cinder/utils.py @@ -58,6 +58,7 @@ from cinder import flags from cinder import log as logging from cinder.openstack.common import cfg from cinder.openstack.common import importutils +from cinder.openstack.common import timeutils LOG = logging.getLogger(__name__) @@ -376,7 +377,7 @@ def last_completed_audit_period(unit=None): unit, offset = unit.split("@", 1) offset = int(offset) - rightnow = utcnow() + rightnow = timeutils.utcnow() if unit not in ('month', 'day', 'year', 'hour'): raise ValueError('Time period must be hour, day, month or year') if unit == 'month': @@ -490,83 +491,6 @@ def get_my_linklocal(interface): " :%(ex)s") % locals()) -def utcnow(): - """Overridable version of utils.utcnow.""" - if utcnow.override_time: - return utcnow.override_time - return datetime.datetime.utcnow() - - -utcnow.override_time = None - - -def is_older_than(before, seconds): - """Return True if before is older than seconds.""" - return utcnow() - before > datetime.timedelta(seconds=seconds) - - -def utcnow_ts(): - """Timestamp version of our utcnow function.""" - return time.mktime(utcnow().timetuple()) - - -def set_time_override(override_time=datetime.datetime.utcnow()): - """Override utils.utcnow to return a constant time.""" - utcnow.override_time = override_time - - -def advance_time_delta(timedelta): - """Advance overriden time using a datetime.timedelta.""" - assert(not utcnow.override_time is None) - utcnow.override_time += timedelta - - -def advance_time_seconds(seconds): - """Advance overriden time by seconds.""" - advance_time_delta(datetime.timedelta(0, seconds)) - - -def clear_time_override(): - """Remove the overridden time.""" - utcnow.override_time = None - - -def strtime(at=None, fmt=PERFECT_TIME_FORMAT): - """Returns formatted utcnow.""" - if not at: - at = utcnow() - return at.strftime(fmt) - - -def parse_strtime(timestr, fmt=PERFECT_TIME_FORMAT): - """Turn a formatted time back into a datetime.""" - return datetime.datetime.strptime(timestr, fmt) - - -def isotime(at=None): - """Stringify time in ISO 8601 format""" - if not at: - at = datetime.datetime.utcnow() - str = at.strftime(ISO_TIME_FORMAT) - tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' - str += ('Z' if tz == 'UTC' else tz) - return str - - -def parse_isotime(timestr): - """Turn an iso formatted time back into a datetime.""" - try: - return iso8601.parse_date(timestr) - except (iso8601.ParseError, TypeError) as e: - raise ValueError(e.message) - - -def normalize_time(timestamp): - """Normalize time in arbitrary timezone to UTC""" - offset = timestamp.utcoffset() - return timestamp.replace(tzinfo=None) - offset if offset else timestamp - - def parse_mailmap(mailmap='.mailmap'): mapping = {} if os.path.exists(mailmap): @@ -1571,7 +1495,7 @@ def service_is_up(service): """Check whether a service is up based on last heartbeat.""" last_heartbeat = service['updated_at'] or service['created_at'] # Timestamps in DB are UTC. - elapsed = total_seconds(utcnow() - last_heartbeat) + elapsed = total_seconds(timeutils.utcnow() - last_heartbeat) return abs(elapsed) <= FLAGS.service_down_time diff --git a/cinder/volume/api.py b/cinder/volume/api.py index 857da172b..2dfe43679 100644 --- a/cinder/volume/api.py +++ b/cinder/volume/api.py @@ -28,6 +28,7 @@ from cinder import exception from cinder import flags from cinder import log as logging import cinder.policy +from cinder.openstack.common import timeutils from cinder import quota from cinder import rpc from cinder import utils @@ -142,7 +143,7 @@ class API(base.Base): msg = _("Volume still has %d dependent snapshots") % len(snapshots) raise exception.InvalidVolume(reason=msg) - now = utils.utcnow() + now = timeutils.utcnow() self.db.volume_update(context, volume_id, {'status': 'deleting', 'terminated_at': now}) host = volume['host'] diff --git a/cinder/volume/manager.py b/cinder/volume/manager.py index d4f6ab592..f4c4bc82e 100644 --- a/cinder/volume/manager.py +++ b/cinder/volume/manager.py @@ -45,6 +45,7 @@ from cinder import log as logging from cinder import manager from cinder.openstack.common import cfg from cinder.openstack.common import importutils +from cinder.openstack.common import timeutils from cinder import rpc from cinder import utils from cinder.volume import volume_types @@ -138,7 +139,7 @@ class VolumeManager(manager.SchedulerDependentManager): self.db.volume_update(context, volume_ref['id'], {'status': 'error'}) - now = utils.utcnow() + now = timeutils.utcnow() self.db.volume_update(context, volume_ref['id'], {'status': 'available', 'launched_at': now}) -- 2.45.2