From: Angus Salkeld Date: Fri, 27 Apr 2012 00:21:43 +0000 (+1000) Subject: openstack-common: timeutils and importutils seperated out X-Git-Tag: 2014.1~1913 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=1f141a6d041e9bbd6b7710c09c35cdd45f6fdab9;p=openstack-build%2Fheat-build.git openstack-common: timeutils and importutils seperated out Signed-off-by: Angus Salkeld --- diff --git a/heat/api/middleware/context.py b/heat/api/middleware/context.py index c8c4d188..cc331e4b 100644 --- a/heat/api/middleware/context.py +++ b/heat/api/middleware/context.py @@ -17,7 +17,7 @@ Middleware that attaches a context to the WSGI request """ -from heat.common import utils +from heat.common import importutils from heat.common import wsgi from heat.common import context @@ -35,7 +35,7 @@ class ContextMiddleware(wsgi.Middleware): # Determine the context class to use ctxcls = context.RequestContext if 'context_class' in self.options: - ctxcls = utils.import_class(self.options['context_class']) + ctxcls = importutils.import_class(self.options['context_class']) return ctxcls(*args, **kwargs) diff --git a/heat/common/context.py b/heat/common/context.py index 99c82ace..abedbc06 100644 --- a/heat/common/context.py +++ b/heat/common/context.py @@ -16,7 +16,7 @@ from heat.common import exception from heat.common import wsgi from heat.openstack.common import cfg -from heat.openstack.common import utils +from heat.openstack.common import importutils class RequestContext(object): @@ -64,7 +64,7 @@ class ContextMiddleware(wsgi.Middleware): # Determine the context class to use self.ctxcls = RequestContext if 'context_class' in local_conf: - self.ctxcls = utils.import_class(local_conf['context_class']) + self.ctxcls = importutils.import_class(local_conf['context_class']) super(ContextMiddleware, self).__init__(app) diff --git a/heat/common/utils.py b/heat/common/utils.py index 05262d65..f39104c7 100644 --- a/heat/common/utils.py +++ b/heat/common/utils.py @@ -30,6 +30,7 @@ from eventlet import semaphore from eventlet.green import subprocess from heat.openstack.common import exception +from heat.openstack.common import timeutils PERFECT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%f" @@ -71,7 +72,7 @@ def gen_uuid(): def strtime(at=None, fmt=PERFECT_TIME_FORMAT): """Returns formatted utcnow.""" if not at: - at = utcnow() + at = timeutils.utcnow() return at.strftime(fmt) @@ -80,16 +81,6 @@ def parse_strtime(timestr, fmt=PERFECT_TIME_FORMAT): 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 - - class LoopingCallDone(Exception): """Exception to break out and stop a LoopingCall. diff --git a/heat/common/wsgi.py b/heat/common/wsgi.py index 45989e7e..6716d0e3 100644 --- a/heat/common/wsgi.py +++ b/heat/common/wsgi.py @@ -41,6 +41,7 @@ import webob.exc from heat.common import exception from heat.openstack.common import cfg +from heat.openstack.common import importutils from heat.openstack.common import utils bind_opts = [ @@ -544,7 +545,7 @@ class BasePasteFactory(object): we strip() the value before using it. """ class_name = local_conf[self.KEY].replace(':', '.').strip() - return utils.import_class(class_name) + return importutils.import_class(class_name) class AppFactory(BasePasteFactory): diff --git a/heat/context.py b/heat/context.py index 50c3fa72..a160820c 100644 --- a/heat/context.py +++ b/heat/context.py @@ -24,6 +24,7 @@ import logging from heat.openstack.common import local from heat.openstack.common import utils +from heat.openstack.common import timeutils from heat.common import utils as heat_utils @@ -73,7 +74,7 @@ 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 = heat_utils.parse_strtime(timestamp) self.timestamp = timestamp diff --git a/heat/db/sqlalchemy/models.py b/heat/db/sqlalchemy/models.py index c0b5665a..bd55fcbf 100644 --- a/heat/db/sqlalchemy/models.py +++ b/heat/db/sqlalchemy/models.py @@ -22,7 +22,7 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.schema import ForeignKeyConstraint from sqlalchemy import types as types from json import dumps, loads -from heat.openstack.common import utils +from heat.openstack.common import timeutils from heat.db.sqlalchemy.session import get_session from sqlalchemy.orm.session import Session @@ -43,8 +43,8 @@ class HeatBase(object): """Base class for Heat 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) def save(self, session=None): """Save this object.""" @@ -64,7 +64,7 @@ class HeatBase(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/heat/openstack/common/importutils.py b/heat/openstack/common/importutils.py new file mode 100644 index 00000000..0561c4df --- /dev/null +++ b/heat/openstack/common/importutils.py @@ -0,0 +1,45 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# 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. + +""" +Import related utilities and helper functions. +""" + +import sys + +from heat.openstack.common import exception + + +def import_class(import_str): + """Returns a class from a string including module and class""" + mod_str, _sep, class_str = import_str.rpartition('.') + try: + __import__(mod_str) + return getattr(sys.modules[mod_str], class_str) + except (ImportError, ValueError, AttributeError): + raise exception.NotFound('Class %s cannot be found' % class_str) + + +def import_object(import_str, *args, **kwargs): + """Import a class and return an instance of it.""" + return import_class(import_str)(*args, **kwargs) + + +def import_module(import_str): + """Import a module.""" + __import__(import_str) + return sys.modules[import_str] diff --git a/heat/openstack/common/timeutils.py b/heat/openstack/common/timeutils.py new file mode 100644 index 00000000..c536cb24 --- /dev/null +++ b/heat/openstack/common/timeutils.py @@ -0,0 +1,73 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# 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. + +""" +Time related utilities and helper functions. +""" + +import datetime + +import iso8601 + + +TIME_FORMAT = "%Y-%m-%dT%H:%M:%S" + + +def isotime(at=None): + """Stringify time in ISO 8601 format""" + if not at: + at = datetime.datetime.utcnow() + str = at.strftime(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): + """Parse time from ISO 8601 format""" + try: + return iso8601.parse_date(timestr) + except iso8601.ParseError as e: + raise ValueError(e.message) + except 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 utcnow(): + """Overridable version of utils.utcnow.""" + if utcnow.override_time: + return utcnow.override_time + return datetime.datetime.utcnow() + + +utcnow.override_time = None + + +def set_time_override(override_time=datetime.datetime.utcnow()): + """Override utils.utcnow to return a constant time.""" + utcnow.override_time = override_time + + +def clear_time_override(): + """Remove the overridden time.""" + utcnow.override_time = None diff --git a/heat/openstack/common/utils.py b/heat/openstack/common/utils.py index ed238ebc..7e5f0611 100644 --- a/heat/openstack/common/utils.py +++ b/heat/openstack/common/utils.py @@ -19,21 +19,17 @@ System-level utilities and helper functions. """ -import datetime import logging import os import random import shlex -import sys from eventlet import greenthread from eventlet.green import subprocess -import iso8601 from heat.openstack.common import exception -TIME_FORMAT = "%Y-%m-%dT%H:%M:%S" LOG = logging.getLogger(__name__) @@ -142,92 +138,3 @@ def execute(*cmd, **kwargs): # call clean something up in between calls, without # it two execute calls in a row hangs the second one greenthread.sleep(0) - - -def import_class(import_str): - """Returns a class from a string including module and class""" - mod_str, _sep, class_str = import_str.rpartition('.') - try: - __import__(mod_str) - return getattr(sys.modules[mod_str], class_str) - except (ImportError, ValueError, AttributeError): - raise exception.NotFound('Class %s cannot be found' % class_str) - - -def import_object(import_str): - """Returns an object including a module or module and class""" - try: - __import__(import_str) - return sys.modules[import_str] - except ImportError: - return import_class(import_str) - - -def isotime(at=None): - """Stringify time in ISO 8601 format""" - if not at: - at = datetime.datetime.utcnow() - str = at.strftime(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): - """Parse time from ISO 8601 format""" - try: - return iso8601.parse_date(timestr) - except iso8601.ParseError as e: - raise ValueError(e.message) - except 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 utcnow(): - """Overridable version of utils.utcnow.""" - if utcnow.override_time: - return utcnow.override_time - return datetime.datetime.utcnow() - - -utcnow.override_time = None - - -def set_time_override(override_time=datetime.datetime.utcnow()): - """Override utils.utcnow to return a constant time.""" - utcnow.override_time = override_time - - -def clear_time_override(): - """Remove the overridden time.""" - utcnow.override_time = None - - -def auth_str_equal(provided, known): - """Constant-time string comparison. - - :params provided: the first string - :params known: the second string - - :return: True if the strings are equal. - - This function takes two strings and compares them. It is intended to be - used when doing a comparison for authentication purposes to help guard - against timing attacks. When using the function for this purpose, always - provide the user-provided password as the first argument. The time this - function will take is always a factor of the length of this string. - """ - result = 0 - p_len = len(provided) - k_len = len(known) - for i in xrange(p_len): - a = ord(provided[i]) if i < p_len else 0 - b = ord(known[i]) if i < k_len else 0 - result |= a ^ b - return (p_len == k_len) & (result == 0) diff --git a/heat/rpc/__init__.py b/heat/rpc/__init__.py index 085024cb..b45cd65f 100644 --- a/heat/rpc/__init__.py +++ b/heat/rpc/__init__.py @@ -19,7 +19,7 @@ import logging from heat.openstack.common import cfg -from heat.openstack.common import utils +from heat.openstack.common import importutils LOG = logging.getLogger(__name__) @@ -192,7 +192,7 @@ def configure(conf): LOG.debug(_("Configuring RPC %s") % conf.rpc_backend) global _RPCIMPL - _RPCIMPL = utils.import_object(conf.rpc_backend) + _RPCIMPL = importutils.import_module(conf.rpc_backend) def _get_impl(): diff --git a/heat/service.py b/heat/service.py index db6a4f60..35914273 100644 --- a/heat/service.py +++ b/heat/service.py @@ -27,7 +27,7 @@ import logging import greenlet from heat.openstack.common import cfg -from heat.openstack.common import utils +from heat.openstack.common import importutils from heat.common import utils as heat_utils from heat.common import exception @@ -108,7 +108,7 @@ class Service(object): self.binary = binary self.topic = topic self.manager_class_name = manager - manager_class = utils.import_class(self.manager_class_name) + manager_class = importutils.import_class(self.manager_class_name) self.manager = manager_class(host=self.host, *args, **kwargs) self.periodic_interval = periodic_interval super(Service, self).__init__(*args, **kwargs) diff --git a/openstack-common.conf b/openstack-common.conf index 94d5c123..7a0da889 100644 --- a/openstack-common.conf +++ b/openstack-common.conf @@ -1,7 +1,7 @@ [DEFAULT] # The list of modules to copy from openstack-common -modules=cfg,local,iniparser,utils,exception +modules=cfg,local,iniparser,utils,exception,timeutils,importutils # The base module to hold the copy of openstack.common base=heat