Handle isotime deprecation in oslo_utils.timeutils
oslo_utils.timeutils is deprecating isotime(). In reality they are deprecating some other things as well but Trove doesn't (currently) use any of those things. Much has been written on the subject of this deprecation. I think the proposal to merely replace isotime with datetime.datetime.isoformat() is a little simplistic. Well intentioned, but nonetheless I believe that it is simplistic. The primary issue I could find with oslo_utils.timeutils.isotime() was the fact that it was naive. I think it could well have been fixed in oslo_utils but for whatever reason(s) oslo decided not to want to go that route. The primary challenge from Trove's perspective is that I want to respect the existing API contract while at the same time get an implementation of time handling that is not identical in its flaws with oslo_utils.timeutils.isotime(). This change set attempts to address that by making trove.common.timeutils.isotime() that is aware. It also implements a utcnow_aware() function that is aware. ISO 8601 allows for four representations of timezone and those are <time>Z <time>[+-]hh:mm <time>[+-]hhmm <time>[+-]hh Trove conventionally used the first one, even if the time wasn't really a UTC time. That's one of the things being fixed here. In review cp16net asked whether this change removes the 'Z' at the end of time strings generated by the isotime() function. The answer is NO. The new isotime() function performs identical to the old and now deprecated function in oslo_utils.timeutils for UTC (Z) times. There was a utcnow() function in trove.common.utils which just wrapped datetime.datetime.utcnow(). That has been moved now to trove.common.timeutils with the other new time related functions. There were a couple of places in Trove where code was using datetime.now() which was not ideal. Those have been corrected now as well. Unit tests have been proposed for the new routines. Closes-Bug: #1532120 Change-Id: Ic5abf6669edd4f1a9fd62e61f437565aa887aebe
This commit is contained in:
parent
fb870b306e
commit
109ff94951
@ -18,11 +18,11 @@ import copy
|
||||
import traceback
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from trove.common import cfg
|
||||
from trove.common.exception import TroveError
|
||||
from trove.common.i18n import _
|
||||
from trove.common import timeutils
|
||||
from trove.conductor import api as conductor_api
|
||||
from trove import rpc
|
||||
|
||||
|
84
trove/common/timeutils.py
Normal file
84
trove/common/timeutils.py
Normal file
@ -0,0 +1,84 @@
|
||||
# Copyright 2016 Tesora Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 datetime import datetime
|
||||
from datetime import timedelta
|
||||
from datetime import tzinfo
|
||||
|
||||
|
||||
class zulutime(tzinfo):
|
||||
"""A tzinfo class for zulu time"""
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return timedelta(0)
|
||||
|
||||
def tzname(self, dt):
|
||||
return "Z"
|
||||
|
||||
def dst(self, dt):
|
||||
return timedelta(0)
|
||||
|
||||
|
||||
def utcnow_aware():
|
||||
"""An aware utcnow() that uses zulutime for the tzinfo."""
|
||||
return datetime.now(zulutime())
|
||||
|
||||
|
||||
def utcnow():
|
||||
"""A wrapper around datetime.datetime.utcnow(). We're doing this
|
||||
because it is mock'ed in some places.
|
||||
"""
|
||||
return datetime.utcnow()
|
||||
|
||||
|
||||
def isotime(tm=None, subsecond=False):
|
||||
"""Stringify a time and return it in an ISO 8601 format. Subsecond
|
||||
information is only provided if the subsecond parameter is set
|
||||
to True (default: False).
|
||||
|
||||
If a time (tm) is provided, it will be stringified. If tm is
|
||||
not provided, the current UTC time is used instead.
|
||||
|
||||
The timezone for UTC time will be provided as 'Z' and not
|
||||
[+-]00:00. Time zone differential for non UTC times will be
|
||||
provided as the full six character string format provided by
|
||||
datetime.datetime.isoformat() namely [+-]NN:NN.
|
||||
|
||||
If an invalid time is provided such that tm.utcoffset() causes
|
||||
a ValueError, that exception will be propagated.
|
||||
"""
|
||||
|
||||
_dt = tm if tm else utcnow_aware()
|
||||
|
||||
if not subsecond:
|
||||
_dt = _dt.replace(microsecond=0)
|
||||
|
||||
# might cause an exception if _dt has a bad utcoffset.
|
||||
delta = _dt.utcoffset() if _dt.utcoffset() else timedelta(0)
|
||||
|
||||
ts = None
|
||||
|
||||
if delta == timedelta(0):
|
||||
# either we are provided a naive time (tm) or no tm, or an
|
||||
# aware UTC time. In any event, we want to use 'Z' for the
|
||||
# timezone rather than the full 6 character offset.
|
||||
_dt = _dt.replace(tzinfo=None)
|
||||
ts = _dt.isoformat()
|
||||
ts += 'Z'
|
||||
else:
|
||||
# an aware non-UTC time was provided
|
||||
ts = _dt.isoformat()
|
||||
|
||||
return ts
|
@ -15,7 +15,6 @@
|
||||
"""I totally stole most of this from melange, thx guys!!!"""
|
||||
|
||||
import collections
|
||||
import datetime
|
||||
import inspect
|
||||
import os
|
||||
import shutil
|
||||
@ -29,7 +28,6 @@ from oslo_log import log as logging
|
||||
from oslo_service import loopingcall
|
||||
from oslo_utils import importutils
|
||||
from oslo_utils import strutils
|
||||
from oslo_utils import timeutils
|
||||
from passlib import pwd
|
||||
import six
|
||||
import six.moves.urllib.parse as urlparse
|
||||
@ -46,7 +44,6 @@ import_object = importutils.import_object
|
||||
import_module = importutils.import_module
|
||||
bool_from_string = strutils.bool_from_string
|
||||
execute = processutils.execute
|
||||
isotime = timeutils.isotime
|
||||
|
||||
|
||||
def build_jinja_environment():
|
||||
@ -99,10 +96,6 @@ def generate_uuid():
|
||||
return str(uuid.uuid4())
|
||||
|
||||
|
||||
def utcnow():
|
||||
return datetime.datetime.utcnow()
|
||||
|
||||
|
||||
def raise_if_process_errored(process, exception):
|
||||
try:
|
||||
err = process.stderr.read()
|
||||
|
@ -13,7 +13,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from datetime import datetime
|
||||
import json
|
||||
|
||||
from oslo_log import log as logging
|
||||
@ -22,6 +21,7 @@ from trove.common import cfg
|
||||
from trove.common import exception
|
||||
from trove.common.exception import ModelNotFoundError
|
||||
from trove.common.i18n import _
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
from trove.datastore import models as dstore_models
|
||||
from trove.db import get_db_api
|
||||
@ -103,7 +103,7 @@ class Configuration(object):
|
||||
|
||||
@staticmethod
|
||||
def delete(context, group):
|
||||
deleted_at = datetime.utcnow()
|
||||
deleted_at = timeutils.utcnow()
|
||||
Configuration.remove_all_items(context, group.id, deleted_at)
|
||||
group.deleted = True
|
||||
group.deleted_at = deleted_at
|
||||
@ -313,7 +313,7 @@ class DatastoreConfigurationParameters(object):
|
||||
config_param = DatastoreConfigurationParameters.load_parameter_by_name(
|
||||
version_id, config_param_name)
|
||||
config_param.deleted = True
|
||||
config_param.deleted_at = datetime.utcnow()
|
||||
config_param.deleted_at = timeutils.utcnow()
|
||||
config_param.save()
|
||||
|
||||
@classmethod
|
||||
|
@ -13,8 +13,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
@ -27,6 +25,7 @@ from trove.common import notification
|
||||
from trove.common.notification import StartNotification, EndNotification
|
||||
from trove.common import pagination
|
||||
from trove.common import policy
|
||||
from trove.common import timeutils
|
||||
from trove.common import wsgi
|
||||
from trove.configuration import models
|
||||
from trove.configuration.models import DBConfigurationParameter
|
||||
@ -194,7 +193,7 @@ class ConfigurationsController(wsgi.Controller):
|
||||
name=group.name, description=group.description):
|
||||
items = self._configuration_items_list(group,
|
||||
body['configuration'])
|
||||
deleted_at = datetime.utcnow()
|
||||
deleted_at = timeutils.utcnow()
|
||||
models.Configuration.remove_all_items(context, group.id,
|
||||
deleted_at)
|
||||
models.Configuration.save(group, items)
|
||||
|
@ -21,6 +21,7 @@ from trove.common import cfg
|
||||
from trove.common import exception
|
||||
from trove.common.i18n import _
|
||||
from trove.common.remote import create_nova_client
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
from trove.db import get_db_api
|
||||
from trove.db import models as dbmodels
|
||||
@ -631,7 +632,7 @@ class DatastoreVersionMetadata(object):
|
||||
key=key, value=value)
|
||||
if db_record.deleted == 1:
|
||||
db_record.deleted = 0
|
||||
db_record.updated_at = utils.utcnow()
|
||||
db_record.updated_at = timeutils.utcnow()
|
||||
db_record.save()
|
||||
return
|
||||
else:
|
||||
|
@ -19,6 +19,7 @@ from trove.common import exception
|
||||
from trove.common.i18n import _
|
||||
from trove.common import models
|
||||
from trove.common import pagination
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
from trove.db import db_query
|
||||
from trove.db import get_db_api
|
||||
@ -33,7 +34,7 @@ class DatabaseModelBase(models.ModelBase):
|
||||
def create(cls, **values):
|
||||
init_vals = {
|
||||
'id': utils.generate_uuid(),
|
||||
'created': utils.utcnow(),
|
||||
'created': timeutils.utcnow(),
|
||||
}
|
||||
if hasattr(cls, 'deleted'):
|
||||
init_vals['deleted'] = False
|
||||
@ -58,20 +59,20 @@ class DatabaseModelBase(models.ModelBase):
|
||||
def save(self):
|
||||
if not self.is_valid():
|
||||
raise exception.InvalidModelError(errors=self.errors)
|
||||
self['updated'] = utils.utcnow()
|
||||
self['updated'] = timeutils.utcnow()
|
||||
LOG.debug("Saving %(name)s: %(dict)s",
|
||||
{'name': self.__class__.__name__,
|
||||
'dict': strutils.mask_dict_password(self.__dict__)})
|
||||
return self.db_api.save(self)
|
||||
|
||||
def delete(self):
|
||||
self['updated'] = utils.utcnow()
|
||||
self['updated'] = timeutils.utcnow()
|
||||
LOG.debug("Deleting %(name)s: %(dict)s",
|
||||
{'name': self.__class__.__name__,
|
||||
'dict': strutils.mask_dict_password(self.__dict__)})
|
||||
|
||||
if self.preserve_on_delete:
|
||||
self['deleted_at'] = utils.utcnow()
|
||||
self['deleted_at'] = timeutils.utcnow()
|
||||
self['deleted'] = True
|
||||
return self.db_api.save(self)
|
||||
else:
|
||||
@ -81,7 +82,7 @@ class DatabaseModelBase(models.ModelBase):
|
||||
for key in values:
|
||||
if hasattr(self, key):
|
||||
setattr(self, key, values[key])
|
||||
self['updated'] = utils.utcnow()
|
||||
self['updated'] = timeutils.utcnow()
|
||||
return self.db_api.save(self)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
@ -18,7 +18,7 @@ from oslo_log import log as logging
|
||||
from trove.common.db import models as guest_models
|
||||
from trove.common import exception
|
||||
from trove.common.remote import create_guest_client
|
||||
from trove.common import utils
|
||||
from trove.common import timeutils
|
||||
from trove.db import get_db_api
|
||||
from trove.instance import models as base_models
|
||||
|
||||
@ -106,7 +106,7 @@ class RootHistory(object):
|
||||
def __init__(self, instance_id, user):
|
||||
self.id = instance_id
|
||||
self.user = user
|
||||
self.created = utils.utcnow()
|
||||
self.created = timeutils.utcnow()
|
||||
|
||||
def save(self):
|
||||
LOG.debug("Saving %(name)s: %(dict)s",
|
||||
|
@ -19,7 +19,7 @@ from trove.common import cfg
|
||||
from trove.common import exception
|
||||
from trove.common.i18n import _
|
||||
from trove.common import remote
|
||||
from trove.common import utils
|
||||
from trove.common import timeutils
|
||||
from trove.extensions.mysql import models as mysql_models
|
||||
from trove.instance import models as instance_models
|
||||
from trove import rpc
|
||||
@ -186,12 +186,11 @@ class NotificationTransformer(object):
|
||||
|
||||
@staticmethod
|
||||
def _get_audit_period():
|
||||
now = datetime.datetime.now()
|
||||
audit_start = utils.isotime(
|
||||
now - datetime.timedelta(
|
||||
seconds=CONF.exists_notification_interval),
|
||||
subsecond=True)
|
||||
audit_end = utils.isotime(now, subsecond=True)
|
||||
now = timeutils.utcnow()
|
||||
start_time = now - datetime.timedelta(
|
||||
seconds=CONF.exists_notification_interval)
|
||||
audit_start = timeutils.isotime(start_time)
|
||||
audit_end = timeutils.isotime(now)
|
||||
return audit_start, audit_end
|
||||
|
||||
def _get_service_id(self, datastore_manager, id_map):
|
||||
|
@ -15,13 +15,13 @@
|
||||
#
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from trove.backup.state import BackupState
|
||||
from trove.common import cfg
|
||||
from trove.common.i18n import _
|
||||
from trove.common.strategies.storage import get_storage_strategy
|
||||
from trove.conductor import api as conductor_api
|
||||
from trove.guestagent.common import timeutils
|
||||
from trove.guestagent.dbaas import get_filesystem_volume_stats
|
||||
from trove.guestagent.strategies.backup.base import BackupError
|
||||
from trove.guestagent.strategies.backup.base import UnknownBackupType
|
||||
@ -74,7 +74,7 @@ class BackupAgent(object):
|
||||
'state': BackupState.BUILDING,
|
||||
}
|
||||
conductor.update_backup(CONF.guest_id,
|
||||
sent=timeutils.float_utcnow(),
|
||||
sent=timeutils.utcnow_ts(microsecond=True),
|
||||
**backup_state)
|
||||
LOG.debug("Updated state for %s to %s.", backup_id, backup_state)
|
||||
|
||||
@ -120,7 +120,8 @@ class BackupAgent(object):
|
||||
finally:
|
||||
LOG.info(_("Completed backup %(backup_id)s."), backup_state)
|
||||
conductor.update_backup(CONF.guest_id,
|
||||
sent=timeutils.float_utcnow(),
|
||||
sent=timeutils.utcnow_ts(
|
||||
microsecond=True),
|
||||
**backup_state)
|
||||
LOG.debug("Updated state for %s to %s.",
|
||||
backup_id, backup_state)
|
||||
|
@ -1,19 +0,0 @@
|
||||
# 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 datetime import datetime
|
||||
|
||||
from oslo_utils import timeutils
|
||||
|
||||
|
||||
def float_utcnow():
|
||||
return float(datetime.strftime(timeutils.utcnow(), "%s.%f"))
|
@ -18,6 +18,7 @@ import os
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from trove.common import cfg
|
||||
from trove.common import context as trove_context
|
||||
@ -26,7 +27,7 @@ from trove.common import instance
|
||||
from trove.conductor import api as conductor_api
|
||||
from trove.guestagent.common import guestagent_utils
|
||||
from trove.guestagent.common import operating_system
|
||||
from trove.guestagent.common import timeutils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
@ -167,7 +168,8 @@ class BaseDbStatus(object):
|
||||
|
||||
heartbeat = {'service_status': status.description}
|
||||
conductor_api.API(context).heartbeat(
|
||||
CONF.guest_id, heartbeat, sent=timeutils.float_utcnow())
|
||||
CONF.guest_id, heartbeat,
|
||||
sent=timeutils.utcnow_ts(microsecond=True))
|
||||
LOG.debug("Successfully cast set_status.")
|
||||
self.status = status
|
||||
else:
|
||||
|
@ -12,7 +12,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from datetime import datetime
|
||||
import enum
|
||||
import hashlib
|
||||
import os
|
||||
@ -26,6 +25,7 @@ from trove.common import exception
|
||||
from trove.common.i18n import _
|
||||
from trove.common.remote import create_swift_client
|
||||
from trove.common import stream_codecs
|
||||
from trove.common import timeutils
|
||||
from trove.guestagent.common import operating_system
|
||||
from trove.guestagent.common.operating_system import FileMode
|
||||
|
||||
@ -404,7 +404,7 @@ class GuestLog(object):
|
||||
'log': self._name}
|
||||
|
||||
def _object_name(self):
|
||||
return 'log-%s' % str(datetime.utcnow()).replace(' ', 'T')
|
||||
return 'log-%s' % str(timeutils.utcnow()).replace(' ', 'T')
|
||||
|
||||
def _get_meta_details(self):
|
||||
LOG.debug("Getting meta details for '%s'", self._name)
|
||||
|
@ -20,6 +20,7 @@ from oslo_log import log as logging
|
||||
from trove.common import cfg
|
||||
from trove.common import exception
|
||||
from trove.common.i18n import _
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
from trove.db import get_db_api
|
||||
from trove.db import models as dbmodels
|
||||
@ -56,7 +57,7 @@ class AgentHeartBeat(dbmodels.DatabaseModelBase):
|
||||
def save(self):
|
||||
if not self.is_valid():
|
||||
raise exception.InvalidModelError(errors=self.errors)
|
||||
self['updated_at'] = utils.utcnow()
|
||||
self['updated_at'] = timeutils.utcnow()
|
||||
LOG.debug("Saving %(name)s: %(dict)s",
|
||||
{'name': self.__class__.__name__, 'dict': self.__dict__})
|
||||
return get_db_api().save(self)
|
||||
|
@ -39,6 +39,7 @@ from trove.common.remote import create_guest_client
|
||||
from trove.common.remote import create_nova_client
|
||||
from trove.common import server_group as srv_grp
|
||||
from trove.common import template
|
||||
from trove.common import timeutils
|
||||
from trove.common.trove_remote import create_trove_client
|
||||
from trove.common import utils
|
||||
from trove.configuration.models import Configuration
|
||||
@ -651,7 +652,7 @@ class BaseInstance(SimpleInstance):
|
||||
pass
|
||||
|
||||
def delete_async(self):
|
||||
deleted_at = datetime.utcnow()
|
||||
deleted_at = timeutils.utcnow()
|
||||
self._delete_resources(deleted_at)
|
||||
LOG.debug("Setting instance %s to be deleted.", self.id)
|
||||
self.update_db(deleted=True, deleted_at=deleted_at,
|
||||
@ -1217,7 +1218,7 @@ class Instance(BuiltInstance):
|
||||
raise exception.BadRequest(_("Instance %s is not a replica"
|
||||
" source.") % self.id)
|
||||
service = InstanceServiceStatus.find_by(instance_id=self.id)
|
||||
last_heartbeat_delta = datetime.utcnow() - service.updated_at
|
||||
last_heartbeat_delta = timeutils.utcnow() - service.updated_at
|
||||
agent_expiry_interval = timedelta(seconds=CONF.agent_heartbeat_expiry)
|
||||
if last_heartbeat_delta < agent_expiry_interval:
|
||||
raise exception.BadRequest(_("Replica Source %s cannot be ejected"
|
||||
@ -1788,7 +1789,7 @@ class InstanceServiceStatus(dbmodels.DatabaseModelBase):
|
||||
self.status_description = value.description
|
||||
|
||||
def save(self):
|
||||
self['updated_at'] = utils.utcnow()
|
||||
self['updated_at'] = timeutils.utcnow()
|
||||
return get_db_api().save(self)
|
||||
|
||||
status = property(get_status, set_status)
|
||||
|
@ -14,7 +14,8 @@
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from trove.common import timeutils
|
||||
|
||||
|
||||
class LimitView(object):
|
||||
@ -27,7 +28,7 @@ class LimitView(object):
|
||||
next_avail = get_utc(self.rate_limit.get("resetTime", 0))
|
||||
|
||||
return {"limit": {
|
||||
"nextAvailable": timeutils.isotime(at=next_avail),
|
||||
"nextAvailable": timeutils.isotime(next_avail),
|
||||
"remaining": self.rate_limit.get("remaining", 0),
|
||||
"unit": self.rate_limit.get("unit", ""),
|
||||
"value": self.rate_limit.get("value", ""),
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
"""Model classes that form the core of Module functionality."""
|
||||
|
||||
from datetime import datetime
|
||||
import hashlib
|
||||
import six
|
||||
from sqlalchemy.sql.expression import or_
|
||||
@ -27,6 +26,7 @@ from trove.common import cfg
|
||||
from trove.common import crypto_utils
|
||||
from trove.common import exception
|
||||
from trove.common.i18n import _
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
from trove.datastore import models as datastore_models
|
||||
from trove.db import models
|
||||
@ -266,7 +266,7 @@ class Module(object):
|
||||
module.priority_apply, None)
|
||||
Module.enforce_live_update(module.id, module.live_update, module.md5)
|
||||
module.deleted = True
|
||||
module.deleted_at = datetime.utcnow()
|
||||
module.deleted_at = timeutils.utcnow()
|
||||
module.save()
|
||||
|
||||
@staticmethod
|
||||
@ -342,7 +342,7 @@ class Module(object):
|
||||
if module.datastore_version_id:
|
||||
module.datastore_version_id = ds_ver_id
|
||||
|
||||
module.updated = datetime.utcnow()
|
||||
module.updated = timeutils.utcnow()
|
||||
DBModule.save(module)
|
||||
|
||||
@staticmethod
|
||||
@ -424,7 +424,7 @@ class InstanceModule(object):
|
||||
@staticmethod
|
||||
def delete(context, instance_module):
|
||||
instance_module.deleted = True
|
||||
instance_module.deleted_at = datetime.utcnow()
|
||||
instance_module.deleted_at = timeutils.utcnow()
|
||||
instance_module.save()
|
||||
|
||||
@staticmethod
|
||||
@ -440,7 +440,7 @@ class InstanceModule(object):
|
||||
|
||||
@staticmethod
|
||||
def update(context, instance_module):
|
||||
instance_module.updated = datetime.utcnow()
|
||||
instance_module.updated = timeutils.utcnow()
|
||||
DBInstanceModule.save(instance_module)
|
||||
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
|
||||
from trove.common import cfg
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
from trove.db import models as dbmodels
|
||||
|
||||
@ -31,8 +32,8 @@ class Quota(dbmodels.DatabaseModelBase):
|
||||
'hard_limit', 'id']
|
||||
|
||||
def __init__(self, tenant_id, resource, hard_limit,
|
||||
id=utils.generate_uuid(), created=utils.utcnow(),
|
||||
update=utils.utcnow()):
|
||||
id=utils.generate_uuid(), created=timeutils.utcnow(),
|
||||
update=timeutils.utcnow()):
|
||||
self.tenant_id = tenant_id
|
||||
self.resource = resource
|
||||
self.hard_limit = hard_limit
|
||||
|
@ -21,7 +21,6 @@ from eventlet import greenthread
|
||||
from eventlet.timeout import Timeout
|
||||
from novaclient import exceptions as nova_exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import timeutils
|
||||
from swiftclient.client import ClientException
|
||||
|
||||
from trove.backup import models as bkup_models
|
||||
@ -61,6 +60,7 @@ from trove.common.remote import create_guest_client
|
||||
from trove.common import server_group as srv_grp
|
||||
from trove.common.strategies.cluster import strategy
|
||||
from trove.common import template
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
from trove.common.utils import try_recover
|
||||
from trove.extensions.mysql import models as mysql_models
|
||||
@ -315,7 +315,7 @@ class ClusterTasks(Cluster):
|
||||
LOG.debug("setting cluster %s as deleted.", cluster_id)
|
||||
cluster = DBCluster.find_by(id=cluster_id)
|
||||
cluster.deleted = True
|
||||
cluster.deleted_at = utils.utcnow()
|
||||
cluster.deleted_at = timeutils.utcnow()
|
||||
cluster.task_status = tasks.ClusterTasks.NONE
|
||||
cluster.save()
|
||||
LOG.debug("end delete_cluster for id: %s", cluster_id)
|
||||
|
@ -71,8 +71,9 @@ def set_fake_stuff(uuid=None, minute=None, unique_id=None):
|
||||
def monkey_patch_uuid_and_date():
|
||||
import uuid
|
||||
uuid.uuid4 = get_uuid
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
utils.utcnow = get_now
|
||||
timeutils.utcnow = get_now
|
||||
utils.generate_uuid = get_uuid
|
||||
|
||||
|
||||
|
@ -31,6 +31,7 @@ from troveclient.compat import exceptions
|
||||
from trove.common import cfg
|
||||
from trove.common import exception
|
||||
from trove.common.strategies.strategy import Strategy
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
from trove.common.utils import poll_until, build_polling_task
|
||||
from trove.tests.config import CONFIG
|
||||
@ -323,7 +324,7 @@ class TestRunner(object):
|
||||
self.def_timeout = timeout
|
||||
|
||||
self.instance_info.name = "TEST_" + datetime.datetime.strftime(
|
||||
datetime.datetime.now(), '%Y_%m_%d__%H_%M_%S')
|
||||
timeutils.utcnow(), '%Y_%m_%d__%H_%M_%S')
|
||||
self.instance_info.dbaas_datastore = CONFIG.dbaas_datastore
|
||||
self.instance_info.dbaas_datastore_version = (
|
||||
CONFIG.dbaas_datastore_version)
|
||||
|
@ -23,6 +23,7 @@ from trove.backup import state
|
||||
from trove.common import context
|
||||
from trove.common import exception
|
||||
from trove.common import remote
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
from trove.db.models import DatabaseModelBase
|
||||
from trove.instance import models as instance_models
|
||||
@ -54,7 +55,7 @@ class BackupCreateTest(trove_testtools.TestCase):
|
||||
def setUp(self):
|
||||
super(BackupCreateTest, self).setUp()
|
||||
util.init_db()
|
||||
self.context, self.instance_id = _prep_conf(utils.utcnow())
|
||||
self.context, self.instance_id = _prep_conf(timeutils.utcnow())
|
||||
self.created = False
|
||||
|
||||
def tearDown(self):
|
||||
@ -241,7 +242,7 @@ class BackupDeleteTest(trove_testtools.TestCase):
|
||||
def setUp(self):
|
||||
super(BackupDeleteTest, self).setUp()
|
||||
util.init_db()
|
||||
self.context, self.instance_id = _prep_conf(utils.utcnow())
|
||||
self.context, self.instance_id = _prep_conf(timeutils.utcnow())
|
||||
|
||||
def tearDown(self):
|
||||
super(BackupDeleteTest, self).tearDown()
|
||||
@ -272,7 +273,7 @@ class BackupORMTest(trove_testtools.TestCase):
|
||||
def setUp(self):
|
||||
super(BackupORMTest, self).setUp()
|
||||
util.init_db()
|
||||
self.context, self.instance_id = _prep_conf(utils.utcnow())
|
||||
self.context, self.instance_id = _prep_conf(timeutils.utcnow())
|
||||
self.backup = models.DBBackup.create(tenant_id=self.context.tenant,
|
||||
name=BACKUP_NAME,
|
||||
state=BACKUP_STATE,
|
||||
@ -449,7 +450,7 @@ class PaginationTests(trove_testtools.TestCase):
|
||||
def setUp(self):
|
||||
super(PaginationTests, self).setUp()
|
||||
util.init_db()
|
||||
self.context, self.instance_id = _prep_conf(utils.utcnow())
|
||||
self.context, self.instance_id = _prep_conf(timeutils.utcnow())
|
||||
# Create a bunch of backups
|
||||
bkup_info = {
|
||||
'tenant_id': self.context.tenant,
|
||||
@ -507,7 +508,7 @@ class OrderingTests(trove_testtools.TestCase):
|
||||
def setUp(self):
|
||||
super(OrderingTests, self).setUp()
|
||||
util.init_db()
|
||||
now = utils.utcnow()
|
||||
now = timeutils.utcnow()
|
||||
self.context, self.instance_id = _prep_conf(now)
|
||||
info = {
|
||||
'tenant_id': self.context.tenant,
|
||||
|
129
trove/tests/unittests/common/test_timeutils.py
Normal file
129
trove/tests/unittests/common/test_timeutils.py
Normal file
@ -0,0 +1,129 @@
|
||||
# Copyright 2016 Tesora Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 datetime import datetime
|
||||
from datetime import timedelta
|
||||
from datetime import tzinfo
|
||||
|
||||
from trove.common import timeutils
|
||||
from trove.tests.unittests import trove_testtools
|
||||
|
||||
|
||||
class bogus_tzinfo(tzinfo):
|
||||
"""A bogus tzinfo class"""
|
||||
def utcoffset(self, dt):
|
||||
return timedelta(hours=2)
|
||||
|
||||
def tzname(self, dt):
|
||||
return "BOGUS"
|
||||
|
||||
def dst(self, dt):
|
||||
return timedelta(hours=1)
|
||||
|
||||
|
||||
class invalid_tzinfo(tzinfo):
|
||||
"""A bogus tzinfo class"""
|
||||
def utcoffset(self, dt):
|
||||
return timedelta(hours=25)
|
||||
|
||||
def tzname(self, dt):
|
||||
return "INVALID"
|
||||
|
||||
def dst(self, dt):
|
||||
return timedelta(hours=25)
|
||||
|
||||
|
||||
class TestTroveTimeutils(trove_testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestTroveTimeutils, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestTroveTimeutils, self).tearDown()
|
||||
|
||||
def test_utcnow_tz(self):
|
||||
dt = timeutils.utcnow()
|
||||
|
||||
self.assertIsNone(dt.tzinfo)
|
||||
|
||||
def test_utcnow_aware_tz(self):
|
||||
dt = timeutils.utcnow_aware()
|
||||
|
||||
self.assertEqual(timedelta(0), dt.utcoffset())
|
||||
self.assertEqual('Z', dt.tzname())
|
||||
|
||||
def test_isotime(self):
|
||||
dt = timeutils.utcnow_aware()
|
||||
|
||||
expected = "%04d-%02d-%02dT%02d:%02d:%02dZ" % (
|
||||
dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
|
||||
|
||||
self.assertEqual(expected, timeutils.isotime(dt))
|
||||
|
||||
def test_isotime_subsecond(self):
|
||||
dt = timeutils.utcnow_aware()
|
||||
|
||||
expected = "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ" % (
|
||||
dt.year, dt.month, dt.day,
|
||||
dt.hour, dt.minute, dt.second,
|
||||
dt.microsecond)
|
||||
|
||||
self.assertEqual(expected, timeutils.isotime(dt, subsecond=True))
|
||||
|
||||
def test_isotime_unaware(self):
|
||||
dt = timeutils.utcnow()
|
||||
|
||||
expected = "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ" % (
|
||||
dt.year, dt.month, dt.day,
|
||||
dt.hour, dt.minute, dt.second,
|
||||
dt.microsecond)
|
||||
|
||||
self.assertEqual(expected, timeutils.isotime(dt, subsecond=True))
|
||||
|
||||
def test_isotime_unaware_subsecond(self):
|
||||
dt = timeutils.utcnow()
|
||||
|
||||
expected = "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ" % (
|
||||
dt.year, dt.month, dt.day,
|
||||
dt.hour, dt.minute, dt.second,
|
||||
dt.microsecond)
|
||||
|
||||
self.assertEqual(expected, timeutils.isotime(dt, subsecond=True))
|
||||
|
||||
def test_bogus_unaware(self):
|
||||
dt = datetime.now(bogus_tzinfo())
|
||||
|
||||
expected = "%04d-%02d-%02dT%02d:%02d:%02d.%06d+02:00" % (
|
||||
dt.year, dt.month, dt.day,
|
||||
dt.hour, dt.minute, dt.second,
|
||||
dt.microsecond)
|
||||
|
||||
self.assertEqual(expected, timeutils.isotime(dt, subsecond=True))
|
||||
|
||||
def test_bogus_unaware_subsecond(self):
|
||||
dt = datetime.now(bogus_tzinfo())
|
||||
|
||||
expected = "%04d-%02d-%02dT%02d:%02d:%02d.%06d+02:00" % (
|
||||
dt.year, dt.month, dt.day,
|
||||
dt.hour, dt.minute, dt.second,
|
||||
dt.microsecond)
|
||||
|
||||
self.assertEqual(expected, timeutils.isotime(dt, subsecond=True))
|
||||
|
||||
def test_throws_exception(self):
|
||||
dt = datetime.now()
|
||||
dt = dt.replace(tzinfo=invalid_tzinfo())
|
||||
|
||||
self.assertRaises(ValueError, timeutils.isotime, dt)
|
@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
|
||||
from mock import patch
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from trove.backup import models as bkup_models
|
||||
from trove.backup import state
|
||||
@ -20,7 +21,6 @@ from trove.common import exception as t_exception
|
||||
from trove.common.instance import ServiceStatuses
|
||||
from trove.common import utils
|
||||
from trove.conductor import manager as conductor_manager
|
||||
from trove.guestagent.common import timeutils
|
||||
from trove.instance import models as t_models
|
||||
from trove.tests.unittests import trove_testtools
|
||||
from trove.tests.unittests.util import util
|
||||
@ -151,7 +151,7 @@ class ConductorMethodTests(trove_testtools.TestCase):
|
||||
build_p = {'service_status': ServiceStatuses.BUILDING.description}
|
||||
iss_id = self._create_iss()
|
||||
iss = self._get_iss(iss_id)
|
||||
now = timeutils.float_utcnow()
|
||||
now = timeutils.utcnow_ts(microsecond=True)
|
||||
future = now + 60
|
||||
self.cond_mgr.heartbeat(None, self.instance_id, new_p, sent=now)
|
||||
self.cond_mgr.heartbeat(None, self.instance_id, build_p, sent=future)
|
||||
@ -164,7 +164,7 @@ class ConductorMethodTests(trove_testtools.TestCase):
|
||||
build_p = {'service_status': ServiceStatuses.BUILDING.description}
|
||||
iss_id = self._create_iss()
|
||||
iss = self._get_iss(iss_id)
|
||||
now = timeutils.float_utcnow()
|
||||
now = timeutils.utcnow_ts(microsecond=True)
|
||||
past = now - 60
|
||||
self.cond_mgr.heartbeat(None, self.instance_id, new_p, sent=past)
|
||||
self.cond_mgr.heartbeat(None, self.instance_id, build_p, sent=past)
|
||||
@ -176,7 +176,7 @@ class ConductorMethodTests(trove_testtools.TestCase):
|
||||
new_name = "renamed"
|
||||
bkup_id = self._create_backup(old_name)
|
||||
bkup = self._get_backup(bkup_id)
|
||||
now = timeutils.float_utcnow()
|
||||
now = timeutils.utcnow_ts(microsecond=True)
|
||||
future = now + 60
|
||||
self.cond_mgr.update_backup(None, self.instance_id, bkup_id,
|
||||
sent=now, name=old_name)
|
||||
@ -190,7 +190,7 @@ class ConductorMethodTests(trove_testtools.TestCase):
|
||||
new_name = "renamed"
|
||||
bkup_id = self._create_backup(old_name)
|
||||
bkup = self._get_backup(bkup_id)
|
||||
now = timeutils.float_utcnow()
|
||||
now = timeutils.utcnow_ts(microsecond=True)
|
||||
past = now - 60
|
||||
self.cond_mgr.update_backup(None, self.instance_id, bkup_id,
|
||||
sent=now, name=old_name)
|
||||
|
@ -16,6 +16,7 @@ from datetime import datetime
|
||||
|
||||
from mock import Mock, MagicMock, patch
|
||||
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
from trove.db import models as dbmodels
|
||||
from trove.db.sqlalchemy import api as dbapi
|
||||
@ -27,7 +28,7 @@ class AgentHeartBeatTest(trove_testtools.TestCase):
|
||||
def setUp(self):
|
||||
super(AgentHeartBeatTest, self).setUp()
|
||||
self.origin_get_db_api = dbmodels.get_db_api
|
||||
self.origin_utcnow = utils.utcnow
|
||||
self.origin_utcnow = timeutils.utcnow
|
||||
self.origin_db_api_save = dbapi.save
|
||||
self.origin_is_valid = dbmodels.DatabaseModelBase.is_valid
|
||||
self.origin_generate_uuid = utils.generate_uuid
|
||||
@ -35,7 +36,7 @@ class AgentHeartBeatTest(trove_testtools.TestCase):
|
||||
def tearDown(self):
|
||||
super(AgentHeartBeatTest, self).tearDown()
|
||||
dbmodels.get_db_api = self.origin_get_db_api
|
||||
utils.utcnow = self.origin_utcnow
|
||||
timeutils.utcnow = self.origin_utcnow
|
||||
dbapi.save = self.origin_db_api_save
|
||||
dbmodels.DatabaseModelBase.is_valid = self.origin_is_valid
|
||||
utils.generate_uuid = self.origin_generate_uuid
|
||||
@ -52,14 +53,14 @@ class AgentHeartBeatTest(trove_testtools.TestCase):
|
||||
|
||||
@patch('trove.db.models.DatabaseModelBase')
|
||||
def test_save(self, dmb_mock):
|
||||
utils.utcnow = Mock()
|
||||
timeutils.utcnow = Mock()
|
||||
dbmodels.get_db_api = MagicMock(
|
||||
return_value=dbmodels.DatabaseModelBase)
|
||||
dbapi.save = Mock()
|
||||
dbmodels.DatabaseModelBase.is_valid = Mock(return_value=True)
|
||||
self.heartBeat = models.AgentHeartBeat()
|
||||
self.heartBeat.save()
|
||||
self.assertEqual(1, utils.utcnow.call_count)
|
||||
self.assertEqual(1, timeutils.utcnow.call_count)
|
||||
|
||||
def test_is_active(self):
|
||||
models.AGENT_HEARTBEAT = 10000000000
|
||||
|
@ -11,7 +11,6 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import datetime
|
||||
import os
|
||||
from tempfile import NamedTemporaryFile
|
||||
import uuid
|
||||
@ -23,7 +22,6 @@ from mock import Mock, MagicMock, patch, PropertyMock, call
|
||||
from novaclient import exceptions as nova_exceptions
|
||||
import novaclient.v2.flavors
|
||||
import novaclient.v2.servers
|
||||
from oslo_utils import timeutils
|
||||
from swiftclient.client import ClientException
|
||||
from testtools.matchers import Equals, Is
|
||||
|
||||
@ -39,6 +37,7 @@ from trove.common.instance import ServiceStatuses
|
||||
from trove.common.notification import TroveInstanceModifyVolume
|
||||
from trove.common import remote
|
||||
import trove.common.template as template
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
from trove.datastore import models as datastore_models
|
||||
import trove.db.models
|
||||
@ -651,8 +650,8 @@ class BuiltInstanceTasksTest(trove_testtools.TestCase):
|
||||
datastore_id='id-1',
|
||||
flavor_id='6',
|
||||
manager='mysql',
|
||||
created=datetime.datetime.utcnow(),
|
||||
updated=datetime.datetime.utcnow(),
|
||||
created=timeutils.utcnow(),
|
||||
updated=timeutils.utcnow(),
|
||||
compute_instance_id='computeinst-id-1',
|
||||
tenant_id='testresize-tenant-id',
|
||||
volume_size='1',
|
||||
|
Loading…
x
Reference in New Issue
Block a user