48
50
exit_code = reason.value.exitCode
50
deferred.callback(exit_code)
52
return deferred.callback(exit_code)
51
53
elif exit_code == None and reason.value.signal:
52
54
error = errors.CharmInvocationError(
53
55
self._hook_name, exit_code, signal=reason.value.signal)
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
display_parent_relation_ident = " on %r" % \
179
self._context.relation_ident
181
display_parent_relation_ident = ""
182
for relation_ident in relation_idents:
183
child = yield self._context.get_relation_hook_context(
185
self._relation_contexts[relation_ident] = child
186
self._log.debug("Cached relation hook contexts%s: %r" % (
187
display_parent_relation_ident,
188
sorted(relation_idents)))
148
192
return self._ended
180
224
"""Returns the hook context for the invocation."""
181
225
return self._context
227
def get_relation_hook_context(self, relation_ident):
228
"""Returns a hook context corresponding to `relation_ident`"""
230
return self._relation_contexts[relation_ident]
232
raise RelationStateNotFound()
234
def get_relation_idents(self, relation_name):
235
return self._context.get_relation_idents(relation_name)
183
237
def validate_hook(self, hook_filename):
184
238
"""Verify that the hook_filename exists and is executable. """
185
239
if not os.path.exists(hook_filename):
253
307
# Flush context changes back to zookeeper if hook was successful.
254
308
if result == 0 and self._context:
255
relation_setting_changes = yield self._context.flush()
309
relation_setting_changes = []
310
for context in self._relation_contexts.itervalues():
311
changes = yield context.flush()
313
for change in changes:
314
if context is self._context:
315
relation_setting_changes.append((None, change))
317
# Only log relation idents for relation settings
318
# on child relation hook contexts
319
relation_setting_changes.append(
320
(context.relation_ident, change))
256
321
if relation_setting_changes:
322
if hasattr(self._context, "relation_ident"):
323
display_parent_relation_ident = " on %r" % \
324
self._context.relation_ident
326
display_parent_relation_ident = ""
258
"Flushed values for hook %r\n%s",
328
"Flushed values for hook %r%s\n%s",
259
329
os.path.basename(hook),
260
FormatItems(relation_setting_changes))
330
display_parent_relation_ident,
331
FormatSettingChanges(relation_setting_changes))
262
333
returnValue(result)