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
This commit is contained in:
Zhiteng Huang
2012-07-13 13:58:25 +08:00
parent 008cad1428
commit 519bd2451d
14 changed files with 45 additions and 216 deletions

View File

@@ -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]

View File

@@ -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

View File

@@ -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}

View File

@@ -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')})

View File

@@ -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):

View File

@@ -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:

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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):

View File

@@ -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

View File

@@ -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']

View File

@@ -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})