64
66
self._process_reason(reason, self.ended)
67
class FormatItems(object):
68
"""Wrapper to delay executing __str_ of items until formatted in log."""
69
def __init__(self, items):
69
class FormatSettingChanges(object):
70
"""Wrapper to delay executing __str_ of changes until written, if at all.
72
:param list changes: Each change is a pair (`relation_ident`,
73
`item`), where `item` may be an `AddedItem`, `DeletedItem`, or
74
`ModifiedItem`. If `relation_ident` is None, this implies that
75
it is a setting on the implied (or parent) context; it is
76
sorted first and the relation_ident for the implied context is
79
def __init__(self, changes):
80
self.changes = changes
73
items = sorted(self.items, key=lambda item: item.key)
74
return "\n".join(" %s" % str(item) for item in items)
85
key=lambda (relation_ident, item): (relation_ident, item.key))
87
for relation_ident, item in changes:
88
if relation_ident is None:
89
lines.append(" %s" % str(item))
91
lines.append(" %s on %r" % (str(item), relation_ident))
92
return "\n".join(lines)
77
95
class Invoker(object):
143
162
# properly terminated with loseConnection
144
163
self._reaper = None
165
# Add the initial context to the relation contexts if it's in
167
if isinstance(context, RelationHookContext):
168
self._relation_contexts[context.relation_ident] = context
172
"""Cache relation hook contexts for all relation idents."""
173
# Get all relation idents (None means "all")
174
relation_idents = set((yield self.get_relation_idents(None)))
175
if isinstance(self._context, RelationHookContext):
176
# Exclude the parent context for being looked up as a child
177
relation_idents.discard(self._context.relation_ident)
178
for relation_ident in relation_idents:
179
child = yield self._context.get_relation_hook_context(
181
self._relation_contexts[relation_ident] = child
182
self._log.debug("Cached relation hook contexts: %s" % (
183
sorted(relation_idents)))
148
187
return self._ended
180
219
"""Returns the hook context for the invocation."""
181
220
return self._context
222
def get_relation_hook_context(self, relation_ident):
223
"""Returns a hook context corresponding to `relation_ident`"""
225
return self._relation_contexts[relation_ident]
227
raise RelationStateNotFound()
229
def get_relation_idents(self, relation_name):
230
return self._context.get_relation_idents(relation_name)
183
232
def validate_hook(self, hook_filename):
184
233
"""Verify that the hook_filename exists and is executable. """
185
234
if not os.path.exists(hook_filename):
253
302
# Flush context changes back to zookeeper if hook was successful.
254
303
if result == 0 and self._context:
255
relation_setting_changes = yield self._context.flush()
304
relation_setting_changes = []
305
for context in self._relation_contexts.itervalues():
306
changes = yield context.flush()
308
for change in changes:
309
if context is self._context:
310
relation_setting_changes.append((None, change))
312
# Only log relation idents for relation settings
313
# on child relation hook contexts
314
relation_setting_changes.append(
315
(context.relation_ident, change))
256
316
if relation_setting_changes:
317
if hasattr(self._context, "relation_ident"):
318
display_parent_relation_ident = " on %r" % \
319
self._context.relation_ident
321
display_parent_relation_ident = ""
258
"Flushed values for hook %r\n%s",
323
"Flushed values for hook %r%s\n%s",
259
324
os.path.basename(hook),
260
FormatItems(relation_setting_changes))
325
display_parent_relation_ident,
326
FormatSettingChanges(relation_setting_changes))
262
328
returnValue(result)