Add unicode support for resource name

When using template which has resource name in unicode to create
stack will failed with encode/decode error.
This patch override __str__ & __unicode__ function in related
classes to make them compatible with unicode.

blueprint: template-unicode-support
Change-Id: Ie677d180d2131abd052101996900414e2b2ef4ad
This commit is contained in:
Ethan Lynn 2014-10-13 17:58:57 +08:00
parent 0becf6c08f
commit 04f0271931
4 changed files with 85 additions and 31 deletions

View File

@ -14,6 +14,7 @@
import collections
import itertools
from oslo.utils import encodeutils
import six
from six.moves import xrange
@ -84,7 +85,13 @@ class Node(object):
def __str__(self):
'''Return a human-readable string representation of the node.'''
return '{%s}' % ', '.join(str(n) for n in self)
text = '{%s}' % ', '.join(str(n) for n in self)
return encodeutils.safe_encode(text)
def __unicode__(self):
'''Return a human-readable string representation of the node.'''
text = '{%s}' % ', '.join(unicode(n) for n in self)
return encodeutils.safe_decode(text)
def __repr__(self):
'''Return a string representation of the node.'''
@ -137,7 +144,15 @@ class Graph(collections.defaultdict):
def __str__(self):
'''Convert the graph to a human-readable string.'''
pairs = ('%s: %s' % (str(k), str(v)) for k, v in six.iteritems(self))
return '{%s}' % ', '.join(pairs)
text = '{%s}' % ', '.join(pairs)
return encodeutils.safe_encode(text)
def __unicode__(self):
'''Convert the graph to a human-readable string.'''
pairs = ('%s: %s' % (unicode(k), unicode(v))
for k, v in six.iteritems(self))
text = '{%s}' % ', '.join(pairs)
return encodeutils.safe_decode(text)
@staticmethod
def toposort(graph):
@ -155,7 +170,7 @@ class Graph(collections.defaultdict):
else:
# There are nodes remaining, but none without
# dependencies: a cycle
raise CircularDependencyException(cycle=str(graph))
raise CircularDependencyException(cycle=six.text_type(graph))
class Dependencies(object):
@ -227,10 +242,17 @@ class Dependencies(object):
'''
return str(self._graph)
def __unicode__(self):
'''
Return a human-readable string representation of the dependency graph
'''
return unicode(self._graph)
def __repr__(self):
'''Return a string representation of the object.'''
edge_reprs = (repr(e) for e in self._graph.edges())
return 'Dependencies([%s])' % ', '.join(edge_reprs)
text = 'Dependencies([%s])' % ', '.join(edge_reprs)
return encodeutils.safe_encode(text)
def graph(self, reverse=False):
'''Return a copy of the underlying dependency graph.'''

View File

@ -15,6 +15,7 @@ import base64
import contextlib
from datetime import datetime
from oslo.config import cfg
from oslo.utils import encodeutils
from oslo.utils import excutils
import six
import warnings
@ -365,11 +366,27 @@ class Resource(object):
def __str__(self):
if self.stack.id:
if self.resource_id:
return '%s "%s" [%s] %s' % (self.__class__.__name__, self.name,
text = '%s "%s" [%s] %s' % (self.__class__.__name__, self.name,
self.resource_id, str(self.stack))
return '%s "%s" %s' % (self.__class__.__name__, self.name,
str(self.stack))
return '%s "%s"' % (self.__class__.__name__, self.name)
else:
text = '%s "%s" %s' % (self.__class__.__name__, self.name,
str(self.stack))
else:
text = '%s "%s"' % (self.__class__.__name__, self.name)
return encodeutils.safe_encode(text)
def __unicode__(self):
if self.stack.id:
if self.resource_id:
text = '%s "%s" [%s] %s' % (self.__class__.__name__, self.name,
self.resource_id,
unicode(self.stack))
else:
text = '%s "%s" %s' % (self.__class__.__name__, self.name,
unicode(self.stack))
else:
text = '%s "%s"' % (self.__class__.__name__, self.name)
return encodeutils.safe_decode(text)
def add_dependencies(self, deps):
for dep in self.t.dependencies(self.stack):
@ -441,7 +458,7 @@ class Resource(object):
LOG.debug('%s', six.text_type(ex))
except Exception as ex:
LOG.info('%(action)s: %(info)s', {"action": action,
"info": str(self)},
"info": six.text_type(self)},
exc_info=True)
failure = exception.ResourceFailure(ex, self, action)
self.state_set(action, self.FAILED, six.text_type(failure))
@ -528,10 +545,10 @@ class Resource(object):
action = self.CREATE
if (self.action, self.status) != (self.INIT, self.COMPLETE):
exc = exception.Error(_('State %s invalid for create')
% str(self.state))
% six.text_type(self.state))
raise exception.ResourceFailure(exc, self, action)
LOG.info(_LI('creating %s'), str(self))
LOG.info(_LI('creating %s'), six.text_type(self))
# Re-resolve the template, since if the resource Ref's
# the StackId pseudo parameter, it will change after
@ -723,7 +740,7 @@ class Resource(object):
# Don't try to suspend the resource unless it's in a stable state
if (self.action == self.DELETE or self.status != self.COMPLETE):
exc = exception.Error(_('State %s invalid for suspend')
% str(self.state))
% six.text_type(self.state))
raise exception.ResourceFailure(exc, self, action)
LOG.info(_LI('suspending %s'), six.text_type(self))
@ -739,7 +756,7 @@ class Resource(object):
# Can't resume a resource unless it's SUSPEND_COMPLETE
if self.state != (self.SUSPEND, self.COMPLETE):
exc = exception.Error(_('State %s invalid for resume')
% str(self.state))
% six.text_type(self.state))
raise exception.ResourceFailure(exc, self, action)
LOG.info(_LI('resuming %s'), six.text_type(self))
@ -1039,8 +1056,8 @@ class Resource(object):
reason_string = get_string_details()
self._add_event('signal', self.status, reason_string)
except Exception as ex:
LOG.exception(_('signal %(name)s : %(msg)s') % {'name': str(self),
'msg': ex})
LOG.exception(_('signal %(name)s : %(msg)s')
% {'name': six.text_type(self), 'msg': ex})
failure = exception.ResourceFailure(ex, self)
raise failure

View File

@ -18,6 +18,7 @@ from time import time as wallclock
import types
import eventlet
from oslo.utils import encodeutils
from oslo.utils import excutils
import six
@ -43,7 +44,7 @@ def task_description(task):
return '%s from %s' % (name, task.__self__)
elif isinstance(task, types.FunctionType):
if name is not None:
return str(name)
return six.text_type(name)
return repr(task)
@ -62,7 +63,7 @@ class Timeout(BaseException):
"""
Initialise with the TaskRunner and a timeout period in seconds.
"""
message = _('%s Timed out') % str(task_runner)
message = _('%s Timed out') % six.text_type(task_runner)
super(Timeout, self).__init__(message)
# Note that we don't attempt to handle leap seconds or large clock
@ -148,12 +149,18 @@ class TaskRunner(object):
def __str__(self):
"""Return a human-readable string representation of the task."""
return 'Task %s' % self.name
text = 'Task %s' % self.name
return encodeutils.safe_encode(text)
def __unicode__(self):
"""Return a human-readable string representation of the task."""
text = 'Task %s' % self.name
return encodeutils.safe_decode(text)
def _sleep(self, wait_time):
"""Sleep for the specified number of seconds."""
if ENABLE_SLEEP and wait_time is not None:
LOG.debug('%s sleeping' % str(self))
LOG.debug('%s sleeping' % six.text_type(self))
eventlet.sleep(wait_time)
def __call__(self, wait_time=1, timeout=None):
@ -180,7 +187,7 @@ class TaskRunner(object):
assert self._runner is None, "Task already started"
assert not self._done, "Task already cancelled"
LOG.debug('%s starting' % str(self))
LOG.debug('%s starting' % six.text_type(self))
if timeout is not None:
self._timeout = Timeout(self, timeout)
@ -192,7 +199,7 @@ class TaskRunner(object):
else:
self._runner = False
self._done = True
LOG.debug('%s done (not resumable)' % str(self))
LOG.debug('%s done (not resumable)' % six.text_type(self))
def step(self):
"""
@ -203,18 +210,18 @@ class TaskRunner(object):
assert self._runner is not None, "Task not started"
if self._timeout is not None and self._timeout.expired():
LOG.info(_LI('%s timed out'), str(self))
LOG.info(_LI('%s timed out'), six.text_type(self))
self._done = True
self._timeout.trigger(self._runner)
else:
LOG.debug('%s running' % str(self))
LOG.debug('%s running' % six.text_type(self))
try:
next(self._runner)
except StopIteration:
self._done = True
LOG.debug('%s complete' % str(self))
LOG.debug('%s complete' % six.text_type(self))
return self._done
@ -234,7 +241,7 @@ class TaskRunner(object):
return
if not self.started() or grace_period is None:
LOG.debug('%s cancelled' % str(self))
LOG.debug('%s cancelled' % six.text_type(self))
self._done = True
if self.started():
self._runner.close()
@ -351,12 +358,13 @@ class DependencyTaskGroup(object):
if name is None:
name = '(%s) %s' % (getattr(task, '__name__',
task_description(task)),
str(dependencies))
six.text_type(dependencies))
self.name = name
def __repr__(self):
"""Return a string representation of the task."""
return '%s(%s)' % (type(self).__name__, self.name)
text = '%s(%s)' % (type(self).__name__, self.name)
return encodeutils.safe_encode(text)
def __call__(self):
"""Return a co-routine which runs the task group."""
@ -497,7 +505,8 @@ class PollingTaskGroup(object):
def __repr__(self):
"""Return a string representation of the task group."""
return '%s(%s)' % (type(self).__name__, self.name)
text = '%s(%s)' % (type(self).__name__, self.name)
return encodeutils.safe_encode(text)
def __call__(self):
"""Return a co-routine which runs the task group."""

View File

@ -391,7 +391,13 @@ class Stack(collections.Mapping):
def __str__(self):
'''Return a human-readable string representation of the stack.'''
return 'Stack "%s" [%s]' % (self.name, self.id)
text = 'Stack "%s" [%s]' % (self.name, self.id)
return encodeutils.safe_encode(text)
def __unicode__(self):
'''Return a human-readable string representation of the stack.'''
text = 'Stack "%s" [%s]' % (self.name, self.id)
return encodeutils.safe_encode(text)
def resource_by_refid(self, refid):
'''
@ -991,7 +997,7 @@ class Stack(collections.Mapping):
'''
# No need to suspend if the stack has been suspended
if self.state == (self.SUSPEND, self.COMPLETE):
LOG.info(_LI('%s is already suspended'), str(self))
LOG.info(_LI('%s is already suspended'), six.text_type(self))
return
sus_task = scheduler.TaskRunner(self.stack_task,
@ -1011,7 +1017,7 @@ class Stack(collections.Mapping):
'''
# No need to resume if the stack has been resumed
if self.state == (self.RESUME, self.COMPLETE):
LOG.info(_LI('%s is already resumed'), str(self))
LOG.info(_LI('%s is already resumed'), six.text_type(self))
return
sus_task = scheduler.TaskRunner(self.stack_task,